Язык программирования C#9 и платформа .NET5
После нажатия клавиши <ТаЬ> будет сгенерирован новый метод, как показано на рис. 12.2.
Обратите внимание, что код заглушки имеет корректный формат цели делегата (кроме того, метод объявлен как
, т.к. событие было зарегистрировано внутри статического метода):staticstatic void NewCar_AboutToBlow(string msg){throw new NotImplementedException();}Средство IntelliSense доступно для всех событий .NET Core, ваших событий и событий из библиотек базовых классов.Такая возможность IDE-среды значительно экономит время, избавляя от необходимости выяснять с помощью справочной системы подходящий тип делегата для применения с заданным событием и формат целевого метода делегата.
Создание специальных аргументов событий
По правде говоря, в текущую итерацию класса
можно было бы внести последнее усовершенствование, которое отражает рекомендованный Microsoft шаблон событий. Если вы начнете исследовать события, отправляемые определенным типом из библиотек базовых классов, то обнаружите, что первый параметр лежащего в основе делегата имеет типCar, в то время как второй — тип, производный отSystem.Object.System.EventArgsПараметр
представляет ссылку на объект, который отправляет событие (такой какSystem.Object), а второй параметр — информацию, относящуюся к обрабатываемому событию. Базовый классCarпредставляет событие, которое не сопровождается какой-либо специальной информацией:System.EventArgspublic class EventArgs{public static readonly EventArgs Empty;public EventArgs();}Для простых событий экземпляр
можно передать напрямую. Тем не менее, когда нужно передавать специальные данные, вы должны построить подходящий класс, производный отEventArgs. В этом примере предположим, что есть класс по имениEventArgs, который поддерживает строковое представление сообщения, отправленного получателю:CarEventArgsusing System;namespace CarEvents{public class CarEventArgs : EventArgs{public readonly string msg;public CarEventArgs(string message){msg = message;}}}Теперь можно модифицировать тип делегата
, как показано ниже (события не изменятся):CarEngineHandlerpublic class Car{public delegate void CarEngineHandler(object sender, CarEventArgs e);...}Здесь при инициировании событий внутри метода
необходимо использовать ссылку на текущий объектAccelerate()(посредством ключевого словаCar) и экземпляр типаthis. Например, рассмотрим следующее обновление:CarEventArgspublic void Accelerate(int delta){// Если этот автомобиль сломан, то инициировать событие Exploded.if (carIsDead){Exploded?.Invoke(this, new CarEventArgs("Sorry, this car is dead..."));}...}На вызывающей стороне понадобится лишь модифицировать обработчики событий для приема входных параметров и получения сообщения через поле, доступное только для чтения. Вот пример:
static void CarAboutToBlow(object sender, CarEventArgs e){Console.WriteLine($"{sender} says: {e.msg}");}Если получатель желает взаимодействовать с объектом, отправившим событие, тогда можно выполнить явное приведение
. Такая ссылка позволит вызывать любой открытый метод объекта, который отправил уведомление:System.Objectstatic void CarAboutToBlow(object sender, CarEventArgs e){// Просто для подстраховки перед приведением// произвести проверку во время выполнения.if (sender is Car c){Console.WriteLine($"Critical Message from {c.PetName}: {e.msg}");}}Обобщенный делегат EventHandler<T>
С учетом того, что очень многие специальные делегаты принимают экземпляр
в первом параметре и экземпляр производного отobjectкласса во втором, предыдущий пример можно дополнительно упростить за счет применения обобщенного типаEventArgs, гдеEventHandler<T>— специальный тип, производный отТ. Рассмотрим следующую модификацию типаEventArgs(обратите внимание, что определять специальный тип делегата больше не нужно):Car

