Методы расширения

Методы расширения в 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;
   }
}

В этом примере мы создали довольно простой метод расширения, который подсчитывает количество слов в строке, используя в качестве разделителя пробел. Работа приложения будет выглядеть следующим образом:

Введите любую строку и нажмите Enter
Эта строка будет содержать шесть слов
6

Обратите внимание на то, как мы вызываем новый метод

Console.WriteLine(value.WordCount());

Метод расширения вызывается так, как будто он определен непосредственно в самом классе

Таким образом, можно сказать, что метод расширения это обычный статический метод, который отличается от других статических методов тем, что первый параметр всегда содержит ключевое слово this и является типом к которому применяется метод расширения. В нашем случае — это тип System.String, но для сокращения кода мы просто указали в параметре метода псевдоним типа — string.

Порядок создания методов расширения

Основываясь на нашем примере, можно выделить следующие шаги для создания методов расширения в C#:

  1. Необходимо создать статический класс.  У нас это класс с названием StringExtensions.
  2. Определить в классе один или несколько статических методов у которых первый параметр будет иметь следующее описание: 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, которая возвращает нам массив слов. Если теперь запустить наше приложение, то результат в консоли может выглядеть, например, так:

Введите любую строку и нажмите Enter
строка, состоящая из нескольких слов
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 выдаст вам следующую ошибку:

Итого

Методы расширения используются для того, чтобы добавить новую функциональность для типов. Метод расширения вызывается так, как если бы он был определен непосредственно в том типе данных для которого он создавался. При этом, методы расширения не должны совпадать по сигнатуре с другими методами целевого типа и не использоваться для статических классов.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии