Шрифт:
Интервал:
Закладка:
hee, hee, hee...
Очевидно, что вы не захотите предоставлять другим приложениям возможность изменять то, на что указывает делегат, или вызывать его члены без вашего разрешения. С учетом сказанного общепринятая практика предусматривает объявление переменных-членов, имеющих типы делегатов, как закрытых.
Ключевое слово event
В качестве сокращения, избавляющего от необходимости создавать специальные методы для добавления и удаления методов из списка вызовов делегата, в языке C# предлагается ключевое слово event. В результате обработки компилятором ключевого слова event вы автоматически получаете методы регистрации и отмены регистрации, а также все необходимые переменные-члены для типов делегатов. Такие переменные-члены с типами делегатов всегда объявляются как закрытые и потому они не доступны напрямую из объекта, инициирующего событие. В итоге ключевое слово event может использоваться для упрощения отправки специальным классом уведомлений внешним объектам.
Определение события представляет собой двухэтапный процесс. Во-первых, понадобится определить тип делегата (или задействовать существующий тип), который будет хранить список методов, подлежащих вызову при возникновении события. Во-вторых, необходимо объявить событие (с применением ключевого слова event) в терминах связанного типа делегата.
Чтобы продемонстрировать использование ключевого слова event, создайте новый проект консольного приложения по имени CarEvents. В этой версии класса Car будут определены два события под названиями AboutToBlow и Exploded, которые ассоциированы с единственным типом делегата по имени CarEngineHandler. Ниже показаны начальные изменения, внесенные в класс Car:
using System;
namespace CarEvents
{
public class Car
{
...
// Этот делегат работает в сочетании с событиями Car.
public delegate void CarEngineHandler(string msgForCaller);
<b> // Этот объект Car может отправлять следующие события:</b>
public event CarEngineHandler Exploded;
public event CarEngineHandler AboutToBlow;
...
}
}
Отправка события вызывающему коду сводится просто к указанию события по имени наряду со всеми обязательными параметрами, как определено ассоциированным делегатом. Чтобы удостовериться в том, что вызывающий код действительно зарегистрировал событие, перед вызовом набора методов делегата событие следует проверить на равенство null. Ниже приведена новая версия метода Accelerate() класса Car:
public void Accelerate(int delta)
{
// Если автомобиль сломан, то инициировать событие Exploded.
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})if (_carIsDead)
{
Exploded?.Invoke("Sorry, this car is dead...");
}
else
{
CurrentSpeed += delta;
<b> // Почти сломан?</b>
if (10 == MaxSpeed - CurrentSpeed)
{
AboutToBlow?.Invoke("Careful buddy! Gonna blow!");
}
<b> // Все еще в порядке!</b>
if (CurrentSpeed >= MaxSpeed)
{
_carIsDead = true;
}
else
{
Console.WriteLine("CurrentSpeed = {0}", CurrentSpeed);
}
}
}
Итак, класс Car был сконфигурирован для отправки двух специальных событий без необходимости в определении специальных функций регистрации или в объявлении переменных-членов, имеющих типы делегатов. Применение нового объекта вы увидите очень скоро, но сначала давайте чуть подробнее рассмотрим архитектуру событий.
"За кулисами" событий
Когда компилятор C# обрабатывает ключевое слово event, он генерирует два скрытых метода, один с префиксом add_, а другой с префиксом remove_. За префиксом следует имя события С#. Например, событие Exploded дает в результате два скрытых метода с именами add_Exploded() и remove_Exploded(). Если заглянуть в код CIL метода add_AboutToBlow(), то можно обнаружить вызов метода Delegate.Combine(). Взгляните на частичный код CIL:
.method public hidebysig specialname instance void add_AboutToBlow(
class [System.Runtime]System.EventHandler`1<class CarEvents.
CarEventArgs> 'value') cil
managed
{
...
IL_000b: call class [System.Runtime]System.Delegate
[System.Runtime]System.
Delegate::Combine(class [System.Runtime]System.Delegate,
class [System.Runtime]System.Delegate)
...
- Понимание SQL - Мартин Грубер - Базы данных