// Если этот автомобиль сломан, то инициировать событие Exploded.
if (carIsDead)
{
Exploded?.Invoke(this, new CarEventArgs("Sorry, this car is dead..."));
}
...
}
На вызывающей стороне понадобится лишь модифицировать обработчики событий для приема входных параметров и получения сообщения через поле, доступное только для чтения. Вот пример:
С учетом того, что очень многие специальные делегаты принимают экземпляр
object
в первом параметре и экземпляр производного от
EventArgs
класса во втором, предыдущий пример можно дополнительно упростить за счет применения обобщенного типа
EventHandler<T>
, где
Т
— специальный тип, производный от
EventArgs
. Рассмотрим следующую модификацию типа
Car
(обратите внимание, что определять специальный тип делегата больше не нужно):
public class Car
{
...
public event EventHandler<CarEventArgs> Exploded;
public event EventHandler<CarEventArgs> AboutToBlow;
}
Затем в вызывающем коде тип
EventHandler<CarEventArgs>
можно использовать везде, где ранее указывался
CarEngineHandler
(или снова применять групповое преобразование методов):
Console.WriteLine("***** Prim and Proper Events *****\n");
// Создать объект Car обычным образом.
Car c1 = new Car("SlugBug", 100, 10);
// Зарегистрировать обработчики событий.
c1.AboutToBlow += CarIsAlmostDoomed;
c1.AboutToBlow += CarAboutToBlow;
EventHandler<CarEventArgs> d = CarExploded;
c1.Exploded += d;
...
Итак, к настоящему моменту вы узнали основные аспекты работы с делегатами и событиями в С#. Хотя этого вполне достаточно для решения практически любых задач, связанных с обратными вызовами, в завершение главы мы рассмотрим несколько финальных упрощений, в частности анонимные методы и лямбда-выражения.
Понятие анонимных методов C#
Как было показано ранее, когда вызывающий код желает прослушивать входящие события, он должен определить
специальный метод в классе (или структуре), который соответствует сигнатуре ассоциированного делегата. Ниже приведен пример:
SomeType t = new SomeType;
// Предположим, что SomeDeletage может указывать на методы,
// которые не принимают аргументов и возвращают void.
t.SomeEvent += new SomeDelegate(MyEventHandler);
// Обычно вызывается только объектом SomeDelegate.
static void MyEventHandler
{
// Делать что-нибудь при возникновении события.
}
Однако если подумать, то такие методы, как
MyEventHandler
, редко предназначены для вызова из любой другой части программы кроме делегата. С точки зрения продуктивности вручную определять отдельный метод для вызова объектом делегата несколько хлопотно (хотя и вполне допустимо).
Для решения указанной проблемы событие можно ассоциировать прямо с блоком операторов кода во время регистрации события. Формально такой код называется анонимным методом. Чтобы ознакомиться с синтаксисом, создайте новый проект консольного приложения по имени
AnonymousMethods
, после чего скопируйте в него файлы
Car.cs
и
CarEventArgs.cs
из проекта
CarEvents
(не забыв изменить пространство имен на
AnonymousMethods
). Модифицируйте код в файле
Program.cs
, как показано ниже, для обработки событий, посылаемых из класса
Car
, с использованием анонимных методов вместо специальных именованных обработчиков событий:
Console.WriteLine("Fatal Message from Car: {0}", e.msg);
};
// В конце концов, этот код будет инициировать события.
for (int i = 0; i < 6; i++)
{
c1.Accelerate(20);
}
Console.ReadLine;
На заметку! После финальной фигурной скобки в анонимном методе должна быть помещена точка с запятой, иначе возникнет ошибка на этапе компиляции.
И снова легко заметить, что специальные статические обработчики событий вроде
CarAboutToBlow
или
CarExploded
в вызывающем коде больше не определяются. Взамен с помощью синтаксиса
+=
определяются встроенные неименованные (т.е. анонимные) методы, к которым вызывающий код будет обращаться во время обработки события. Базовый синтаксис анонимного метода представлен следующим псевдокодом: