Язык программирования C#9 и платформа .NET5
c1.AboutToBlow += delegate(object sender, CarEventArgs e){Console.WriteLine("Critical Message from Car: {0}", e.msg);};Доступ к локальным переменным
Анонимные методы интересны тем, что способны обращаться к локальным переменным метода, где они определены. Формально такие переменные называются внешними переменными анонимного метода. Ниже перечислены важные моменты, касающиеся взаимодействия между областью действия анонимного метода и областью действия метода, в котором он определен.
• Анонимный метод не имеет доступа к параметрам
иrefопределяющего метода.out• Анонимный метод не может иметь локальную переменную, имя которой совпадает с именем локальной переменной внешнего метода.
• Анонимный метод может обращаться к переменным экземпляра (или статическим переменным) из области действия внешнего класса.
• Анонимный метод может объявлять локальную переменную с тем же именем, что и у переменной-члена внешнего класса (локальные переменные имеют отдельную область действия и скрывают переменные-члены из внешнего класса).
Предположим, что в операторах верхнего уровня определена локальная переменная по имени
типаaboutToBlowCounter. Внутри анонимных методов, которые обрабатывают событиеint, выполните увеличение значенияAboutToBlowна 1 и вывод результата на консоль перед завершением операторов:aboutToBlowCounterConsole.WriteLine("***** Anonymous Methods *****\n");int aboutToBlowCounter = 0;// Создать объект Car обычным образом.Car c1 = new Car("SlugBug", 100, 10);// Зарегистрировать обработчики событий как анонимные методы.c1.AboutToBlow += delegate{<b> aboutToBlowCounter++;</b>Console.WriteLine("Eek! Going too fast!");};c1.AboutToBlow += delegate(object sender, CarEventArgs e){<b> aboutToBlowCounter++;</b>Console.WriteLine("Critical Message from Car: {0}", e.msg);};...// В конце концов, это будет инициировать события.for (int i = 0; i < 6; i++){c1.Accelerate(20);}Console.WriteLine("AboutToBlow event was fired {0} times.",aboutToBlowCounter);Console.ReadLine();После запуска модифицированного кода вы обнаружите, что финальный вывод
сообщает о двукратном инициировании событияConsole.WriteLine().AboutToBlowИспользование ключевого слова static с анонимными методами (нововведение в версии 9.0)
В предыдущем примере демонстрировались анонимные методы, которые взаимодействовали с переменными, объявленными вне области действия самих методов. Хотя возможно именно это входило в ваши намерения, прием нарушает инкапсуляцию и может привести к нежелательным побочным эффектам в программе. Вспомните из главы 4, что локальные функции могут быть изолированы от содержащего их кода за счет их настройки как статических, например:
static int AddWrapperWithStatic(int x, int y){// Выполнить проверку достоверностиreturn Add(x,y);static int Add(int x, int y){return x + y;}}В версии C# 9.0 анонимные методы также могут быть помечены как статические с целью предохранения инкапсуляции и гарантирования того, что они не привнесут какие-либо побочные эффекты в код, где они содержатся. Вот как выглядит модифицированный анонимный метод:
c1.AboutToBlow += static delegate{// Этот код приводит к ошибке на этапе компиляции,// потому что анонимный метод помечен как статическийaboutToBlowCounter++;Console.WriteLine("Eek! Going too fast!");};Предыдущий код не скомпилируется из-за попытки анонимного метода получить доступ к переменной, объявленной вне области его действия.
Использование отбрасывания с анонимными методами (нововведение в версии 9.0)
Отбрасывание, представленное в главе 3, в версии C# 9.0 было обновлено с целью применения в качестве входных параметров, но с одной уловкой. Поскольку символ подчеркивания (
) в предшествующих версиях C# считался законным идентификатором переменной, в анонимном методе должно присутствовать два и более подчеркиваний, чтобы они трактовались как отбрасывание._Например, в следующем коде создается делегат
, который принимает два целых числа и возвращает еще одно целое число. Приведенная реализация игнорирует любые переданные переменные и возвращает значениеFunc<>:42Console.WriteLine("******** Discards with Anonymous Methods ********");Func<int,int,int> constant = delegate (int _, int _) {return 42;};Console.WriteLine("constant(3,4)={0}",constant(3,4));Понятие лямбда-выражений
Чтобы завершить знакомство с архитектурой событий .NET Core, необходимо исследовать лямбда-выражения. Как объяснялось ранее в главе, язык C# поддерживает возможность обработки событий "встраиваемым образом", позволяя назначать блок операторов кода прямо событию с применением анонимных методов вместо построения отдельного метода, который должен вызываться делегатом. Лямбда-выражения всего лишь лаконичный способ записи анонимных методов, который в конечном итоге упрощает работу с типами делегатов .NET Core.