Заметьте, что, зажигая событие, класс посылает сообщение получателям события - объектам некоторых других классов. Будем называть класс, зажигающий событие, классом - отправителем сообщения (sender). Класс, чьи объекты получают сообщения, будем называть классом - получателем сообщения (receiver). Класс-отправитель сообщения, в принципе, не знает своих получателей. Он отправляет сообщение в межмодульное пространство. Одно и то же сообщение может быть получено и по-разному обработано произвольным числом объектов разных классов. Взгляните на схему, демонстрирующую взаимодействие объектов при посылке и получении сообщения.
Рис. 21.1. Взаимодействие объектов. Посылка и получение сообщения о событии При проектировании класса с событиями, возможно, самое трудное - содержательная сторона дела. Какими событиями должен обладать класс, в каких методах и в какой момент зажигать то или иное событие? Содержательную сторону будем пояснять на содержательных примерах. А сейчас рассмотрим технический вопрос: как объявляются события средствами языка С#? Прежде всего, уточним, что такое событие с программистской точки зрения. Начнем не с самого события, а с его обработчика. Обработчик события - это обычная процедура с аргументами. Понятно, что сообщение, посылаемое при зажигании события, является аналогом вызова процедуры. Поскольку сигнатура посылаемого сообщения должна соответствовать сигнатуре принимаемого сообщения, то объявление события синтаксически должно задавать сигнатуру процедуры. Делегаты и события Наверное, вы уже заметили, что схема работы с событиями вполне укладывается в механизм, определяемый делегатами. В C# каждое событие определяется делегатом, описывающим сигнатуру сообщения. Объявление события - это двухэтапный процесс: - Вначале объявляется делегат - функциональный класс, задающий сигнатуру. Как отмечалось при рассмотрении делегатов, объявление делегата может быть помещено в некоторый класс, например, класс Sender. Но, чаще всего, это объявление находится вне класса в пространстве имен. Поскольку одна и та же сигнатура может быть у разных событий, то для них достаточно иметь одного делегата. Для некоторых событий можно использовать стандартных делегатов, встроенных в каркас. Тогда достаточно знать только их имена.
- Если делегат определен, то в классе Sender, создающем события, достаточно объявить событие как экземпляр соответствующего делегата. Это делается точно так же, как и при объявлении функциональных экземпляров делегата. Исключением является добавление служебного слова event. Формальный синтаксис объявления таков:
[атрибуты] [модификаторы]event [тип, заданный делегатом] [имя события] Есть еще одна форма объявления, но о ней чуть позже. Чаще всего, атрибуты не задаются, а модификатором является модификатор доступа - public. Приведу пример объявления делегата и события, представляющего экземпляр этого делегата: namespace Events { public delegate void FireEventHandler(object Sender, |