создание типа, отслеживающего событие
Самое трудное позади. В этом разделе я покажу, как определить тип, использую-
щий событие, поддерживаемое другим типом. Начнем с изучения исходного кода
типа
Fax
:
internal sealed class Fax {
// Передаем конструктору объект MailManager
продолжение
296
Глава.11 .События
public Fax(MailManager mm) {
// Создаем экземпляр делегата EventHandler,
// ссылающийся на метод обратного вызова FaxMsg
// Регистрируем обратный вызов для события NewMail объекта MailManager
mm.NewMail += FaxMsg;
}
// MailManager вызывает этот метод для уведомления
// объекта Fax о прибытии нового почтового сообщения
private void FaxMsg(Object sender, NewMailEventArgs e) {
// 'sender' используется для взаимодействия с объектом MailManager,
// если потребуется передать ему какую-то информацию
// 'e' определяет дополнительную информацию о событии,
// которую пожелает предоставить MailManager
// Обычно расположенный здесь код отправляет сообщение по факсу
// Тестовая реализация выводит информацию на консоль
Console.WriteLine("Faxing mail message:");
Console.WriteLine(" From={0}, To={1}, Subject={2}",
e.From, e.To, e.Subject);
}
// Этот метод может выполняться для отмены регистрации объекта Fax
// в качестве получтеля уведомлений о событии NewMail
public void Unregister(MailManager mm) {
// Отменить регистрацию на уведомление о событии NewMail объекта
MailManager. mm.NewMail -= FaxMsg;
}
}
При инициализации почтовое приложение сначала создает объект
MailManager
и сохраняет ссылку на него в переменной. Затем оно создает объект
Fax
, передавая
ссылку на
MailManager
как параметр. В конструкторе
Fax
объект
Fax
регистрируется
на уведомления о событии
NewMail
объекта
MailManager
при помощи оператора
+=
языка C#:
mm.NewMail += FaxMsg;
Обладая встроенной поддержкой событий, компилятор C# транслирует опе-
ратор
+=
в код, регистрирующий объект для получения уведомлений о событии:
mm.add_NewMail(new EventHandler(this.FaxMsg));
Как видите, компилятор C# генерирует код, конструирующий делегата
EventHandler
, который инкапсулирует метод
FaxMsg
класса
Fax
. Затем компилятор C# вызывает метод
add_NewMail
объекта
MailManager
, пере-
давая ему нового делегата. Конечно, вы можете убедиться в этом, скомпилировав
код и затем изучив IL-код с помощью такого инструмента, как утилита
ILDasm exe
.
297
Создание.типа,.отслеживающего.событие
Даже используя язык, не поддерживающий события напрямую, можно зареги-
стрировать делегат для уведомления о событии, явно вызвав метод доступа
add
.
Результат не изменяется, только исходный текст получается не столь элегантным.
Именно метод
add
регистрирует делегата для уведомления о событии, добавляя
его в список делегатов данного события.
Когда срабатывает событие объекта
MailManager
, вызывается метод
FaxMsg
объ-
екта
Fax
. Этому методу в первом параметре
sender
передается ссылка на объект
MailManager
. Чаще всего этот параметр игнорируется, но он может и использовать-
ся, если в ответ на уведомление о событии объект
Fax
пожелает получить доступ
к полям или методам объекта
MailManager
. Второй параметр — ссылка на объект
NewMailEventArgs
. Этот объект содержит всю дополнительную информацию, кото-
рая, по мнению
NewMailEventArgs
, может быть полезной для получателей события.
При помощи объекта
NewMailEventArgs
метод
FaxMsg
может без труда получить
доступ к сведениям об отправителе и получателе сообщения, его теме и собственно
тексту. Реальный объект
Fax
отправлял бы эти сведения адресату, но в данном при-
мере они просто выводятся на консоль.
Когда объекту больше не нужны уведомления о событиях, он должен отменить
свою регистрацию. Например, объект
Fax
отменит свою регистрацию в качестве
получателя уведомления о событии
NewMail
, если пользователю больше не нужно
пересылать сообщения электронной почты по факсу. Пока объект зарегистриро-
ван в качестве получателя уведомления о событии другого объекта, он не будет
уничтожен уборщиком мусора. Если в вашем типе реализован метод
Dispose
объ-
екта
IDisposable
, уничтожение объекта должно вызвать отмену его регистрации
в качестве получателя уведомлений обо всех событиях (об объекте
IDisposable
см. также главу 21).
Код, иллюстрирующий отмену регистрации, показан в исходном тексте метода
Unregister
объекта
Fax
. Код этого метода фактически идентичен конструктору
типа
Fax
. Единственное отличие в том, что здесь вместо
+=
использован оператор
–=
. Обнаружив код, отменяющий регистрацию делегата при помощи оператора
–=
,
компилятор C# генерирует вызов метода
remove
этого события:
mm.remove_NewMail(new EventHandler(FaxMsg));
Как и в случае оператора
+=
, даже при использовании языка, не поддерживаю-
щего события напрямую, можно отменить регистрацию делегата явным вызовом
метода доступа
remove
, который отменяет регистрацию делегата путем сканирования
списка в поисках делегата-оболочки метода, соответствующего переданному. Если
совпадение обнаружено, делегат удаляется из списка делегатов события. Если нет,
то список делегатов события остается, а ошибка не происходит.
Кстати, C# требует, чтобы для добавления и удаления делегатов из списка в ва-
ших программах использовались операторы
+=
и
–=
. Если попытаться напрямую
обратиться к методам
add
или
remove
, компилятор C# сгенерирует сообщение об
ошибке (CS0571: оператор или метод доступа нельзя вызывать явно):
CS0571: cannot explicitly call operator or accessor
Do'stlaringiz bilan baham: |