Содержание
Методы расширения в C# позволяют добавлять новую функциональность к классам без создания производных классов, то есть не прибегая к наследованию. Методы расширения бывают очень полезны в том случае, если мы не имеем доступа к какому-либо классу для его изменения, однако нам требуется каким-либо образом расширить возможности этого класса.
Пример метода расширения
Так как в C# все типы данных так или иначе имеют общего предка — класс Object
, то и методы расширения мы можем создавать для любых типов данных. Например, напишем свой метод расширения для типа string
:
Console.WriteLine("Введите любую строку и нажмите Enter"); string value = Console.ReadLine(); //используем метод расширения для string Console.WriteLine(value.WordCount()); public static class StringExtensions { public static int WordCount(this string data) { return data.Split(" ").Length; } }
В этом примере мы создали довольно простой метод расширения, который подсчитывает количество слов в строке, используя в качестве разделителя пробел. Работа приложения будет выглядеть следующим образом:
Эта строка будет содержать шесть слов
6
Обратите внимание на то, как мы вызываем новый метод
Console.WriteLine(value.WordCount());
Метод расширения вызывается так, как будто он определен непосредственно в самом классе
Таким образом, можно сказать, что метод расширения это обычный статический метод, который отличается от других статических методов тем, что первый параметр всегда содержит ключевое слово this
и является типом к которому применяется метод расширения. В нашем случае — это тип System.String
, но для сокращения кода мы просто указали в параметре метода псевдоним типа — string
.
Порядок создания методов расширения
Основываясь на нашем примере, можно выделить следующие шаги для создания методов расширения в C#:
- Необходимо создать статический класс. У нас это класс с названием
StringExtensions
. - Определить в классе один или несколько статических методов у которых первый параметр будет иметь следующее описание:
this целевой_тип имя_параметра
. Здесьцелевой_тип
— этот тип данных для которого создается метод расширения.
Так как методы расширения — это обычные статические методы, размещенные в обычных же статических классах, то ничего нам не мешает создавать различные методы расширения, делать их перегрузки и т.д. Например, изменим наш класс StringExtensions
следующим образом:
Console.WriteLine("Введите любую строку и нажмите Enter"); string value = Console.ReadLine(); //используем метод расширения для string Console.WriteLine(value.WordCount(out string[] info)); foreach (string word in info) Console.WriteLine(word); public static class StringExtensions { public static int WordCount(this string data) { return data.Split(" ").Length; } public static int WordCount(this string data, out string[] words) { words = data.Split(" "); return words.Length; } }
Здесь мы добавили в класс перегруженную версию метода WordCount
, которая возвращает нам массив слов. Если теперь запустить наше приложение, то результат в консоли может выглядеть, например, так:
строка, состоящая из нескольких слов
5
строка,
состоящая
из
нескольких
слов
Ограничение методов расширения
Методы расширения в C# имеют свои ограничения и особенности, которые мы должны учитывать. Так, метод расширения не будет вызываться, если в типе уже определен метод с аналогичной сигнатурой. Например, попробуем изменить у типа string метод Split()
, используя свой метод расширения:
public static class StringExtensions { public static string[] Split(this string data, string? separator) { return new string[] { "произвольный", "набор", "слов"}; } public static int WordCount(this string data) { return data.Split(" ").Length; } public static int WordCount(this string data, out string[] words) { words = data.Split(" "); return words.Length; } }
метод Split()
в классе StringExtensions
всегда возвращает массив строк из трех элементов. Однако, так как в исходном типе string
уже имеется метод с аналогичной сигнатурой, то наш метод расширения никогда не будет вызван. Проверить это легко, запустив приложение и задав любую строку — Вы увидите, что строка обрабатывается «родным» методом Split()
, а не методом расширения.
Еще один важный момент, касающийся методов расширения, заключается в том, что мы не можем создать метод расширения для статического класса. Например, попробуем создать метод расширения для статического класса Console
. Как только вы попытаетесь определить первым параметром метода расширения статический класс, Visual Studio выдаст вам следующую ошибку:
Итого
Методы расширения используются для того, чтобы добавить новую функциональность для типов. Метод расширения вызывается так, как если бы он был определен непосредственно в том типе данных для которого он создавался. При этом, методы расширения не должны совпадать по сигнатуре с другими методами целевого типа и не использоваться для статических классов.