Язык программирования C#9 и платформа .NET5
За счет применения расширяющих методов появляется возможность модифицировать типы, не создавая подклассов и не изменяя код типа напрямую. Загвоздка в том, что новая функциональность предлагается типом, только если в текущем проекте будут присутствовать ссылки на расширяющие методы.
Определение расширяющих методов
Первое ограничение, связанное с расширяющими методами, состоит в том, что они должны быть определены внутри статического класса (см. главу 5), а потому каждый расширяющий метод должен объявляться с ключевым словом
. Вторая проблема в том, что все расширяющие методы помечаются как таковые посредством ключевого словаstaticв качестве модификатора первого (и только первого) параметра заданного метода. Параметр, помеченный с помощьюthis, представляет расширяемый элемент.thisВ целях иллюстрации создайте новый проект консольного приложения под названием
. Предположим, что создается класс по имениExtensionMethods, в котором определены два расширяющих метода. Первый расширяющий метод позволяет объекту любого типа взаимодействовать с новым методомМуExtensions, который использует типы из пространства именDisplayDefiningAssembly()для отображения имени сборки, содержащей данный тип.System.ReflectionНа заметку! API-интерфейс рефлексии формально рассматривается в главе 17. Если эта тема для вас нова, тогда просто запомните, что рефлексия позволяет исследовать структуру сборок, типов и членов типов во время выполнения.
Второй расширяющий метод по имени
позволяет любому значению типаReverseDigits()получить новую версию самого себя с обратным порядком следования цифр. Например, если целочисленное значениеintвызывает1234, то в результате возвратитсяReverseDigits(). Взгляните на следующую реализацию класса (не забудьте импортировать пространство имен4321):System.Reflectionusing System;using System.Reflection;namespace MyExtensionMethods{static class MyExtensions{// Этот метод позволяет объекту любого типа// отобразить сборку, в которой он определенpublic static void DisplayDefiningAssembly(this object obj){Console.WriteLine("{0} lives here: => {1}\n",obj.GetType().Name,Assembly.GetAssembly(obj.GetType()).GetName().Name);}// Этот метод позволяет любому целочисленному значению изменить// порядок следования десятичных цифр на обратный.// Например, для 56 возвратится 65.public static int ReverseDigits(this int i){// Транслировать int в string и затем получить все его символы.char[] digits = i.ToString().ToCharArray();// Изменить порядок следования элементов массива.Array.Reverse(digits);// Поместить обратно в строку.string newDigits = new string(digits);// Возвратить модифицированную строку как int.return int.Parse(newDigits);}}}Снова обратите внимание на то, что первый параметр каждого расширяющего метода снабжен ключевым словом
, находящимся перед определением типа параметра. Первый параметр расширяющего метода всегда представляет расширяемый тип. Учитывая, что методthisбыл прототипирован для расширенияDisplayDefiningAssembly(), этот новый член теперь присутствует в каждом типе, посколькуSystem.Objectявляется родительским для всех типов платформы .NET Core. Однако методObjectпрототипирован для расширения только целочисленных типов, и потому если к нему обращается какое-то другое значение, то возникнет ошибка на этапе компиляции.ReverseDigits()На заметку! Запомните, что каждый расширяющий метод может иметь множество параметров, но только первый параметр разрешено помечать посредством
. Дополнительные параметры будут трактоваться как нормальные входные параметры, применяемые методом.thisВызов расширяющих методов
Располагая созданными расширяющими методами, рассмотрим следующий код, в котором они используются с разнообразными типами из библиотек базовых классов:
using System;using MyExtensionMethods;Console.WriteLine("***** Fun with Extension Methods *****\n");// В int появилась новая отличительная черта!int myInt = 12345678;myInt.DisplayDefiningAssembly();// И в SoundPlayer!System.Data.DataSet d = new System.Data.DataSet();d.DisplayDefiningAssembly();// Использовать новую функциональность int.Console.WriteLine("Value of myInt: {0}", myInt);Console.WriteLine("Reversed digits of myInt: {0}",myInt.ReverseDigits());Console.ReadLine();Ниже показан вывод:
***** Fun with Extension Methods *****