И снова легко заметить, что специальные статические обработчики событий вроде CarAboutToBlow() или CarExploded() в вызывающем коде больше не определяются. Взамен с помощью синтаксиса += определяются встроенные неименованные (т.е. анонимные) методы, к которым вызывающий код будет обращаться во время обработки события. Базовый синтаксис анонимного метода представлен следующим псевдокодом:
Обратите внимание, что при обработке первого события AboutToBlow внутри предыдущего примера кода аргументы, передаваемые из делегата, не указывались:
c1.AboutToBlow += delegate
{
Console.WriteLine("Eek! Going too fast!");
};
Строго говоря, вы не обязаны принимать входные аргументы, отправленные специфическим событием. Но если вы хотите задействовать эти входные аргументы, тогда понадобится указать параметры, прототипированные типом делегата (как показано во второй обработке событий AboutToBlow и Exploded). Например:
c1.AboutToBlow += delegate(object sender, CarEventArgs e)
{
Console.WriteLine("Critical Message from Car: {0}", e.msg);
};
Доступ к локальным переменным
Анонимные методы интересны тем, что способны обращаться к локальным переменным метода, где они определены. Формально такие переменные называются
• Анонимный метод не имеет доступа к параметрам ref и out определяющего метода.
• Анонимный метод не может иметь локальную переменную, имя которой совпадает с именем локальной переменной внешнего метода.
• Анонимный метод может обращаться к переменным экземпляра (или статическим переменным) из области действия внешнего класса.
• Анонимный метод может объявлять локальную переменную с тем же именем, что и у переменной-члена внешнего класса (локальные переменные имеют отдельную область действия и скрывают переменные-члены из внешнего класса).
Предположим, что в операторах верхнего уровня определена локальная переменная по имени aboutToBlowCounter типа int. Внутри анонимных методов, которые обрабатывают событие AboutToBlow, выполните увеличение значения aboutToBlowCounter на 1 и вывод результата на консоль перед завершением операторов:
Console.WriteLine("***** Anonymous Methods *****\n");
int aboutToBlowCounter = 0;
// Создать объект Car обычным образом.
Car c1 = new Car("SlugBug", 100, 10);
// Зарегистрировать обработчики событий как анонимные методы.
c1.AboutToBlow += delegate
{
aboutToBlowCounter++;
Console.WriteLine("Eek! Going too fast!");
};
c1.AboutToBlow += delegate(object sender, CarEventArgs e)
{
aboutToBlowCounter++;
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)
{