Чтение онлайн

на главную - закладки

Жанры

Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:

Обработчик события — это обычная процедура с аргументами. Понятно, что сообщение, посылаемое при зажигании события, является аналогом вызова процедуры. Поскольку сигнатура посылаемого сообщения должна соответствовать сигнатуре принимаемого сообщения, то объявление события синтаксически должно задавать сигнатуру процедуры.

Делегаты и события

Наверное, вы уже заметили, что схема работы с событиями вполне укладывается в механизм, определяемый делегатами. В C# каждое событие определяется делегатом, описывающим сигнатуру сообщения. Объявление

события — это двухэтапный процесс:

• Вначале объявляется делегат — функциональный класс, задающий сигнатуру. Как отмечалось при рассмотрении делегатов, объявление делегата может быть помещено в некоторый класс, например, класс Sender. Но, чаще всего, это объявление находится вне класса в пространстве имен. Поскольку одна и та же сигнатура может быть у разных событий, то для них достаточно иметь одного делегата. Для некоторых событий можно использовать стандартные делегаты, встроенные в каркас. Тогда достаточно знать только их имена.

• Если делегат определен, то в классе Sender, создающем события, достаточно объявить событие как экземпляр соответствующего делегата. Это делается точно так же, как и при объявлении функциональных экземпляров делегата. Исключением является добавление служебного слова event. Формальный синтаксис объявления таков:

[атрибуты] [модификаторы]event [тип, заданный делегатом] [имя события]

Есть еще одна форма объявления, но о ней чуть позже. Чаще всего, атрибуты не задаются, а модификатором является модификатор доступа — public. Приведу пример объявления делегата и события, представляющего экземпляр этого делегата:

namespace Events

{

public delegate void FireEventHandler(object Sender, int time, int build);

public class TownWithEvents

{

public event FireEventHandler FireEvent;

….

}//TownWithEvents

….

}//namespace Events

Здесь делегат FireEventHandler описывает класс событий, сигнатура которых содержит три аргумента. Событие FireEvent в классе TownWithEvents является экземпляром класса, заданного делегатом.

Как зажигаются события

Причины возникновения события могут быть разными. Поэтому вполне вероятно, что одно и то же событие будет зажигаться в разных методах класса в тот момент, когда возникнет одна из причин появления события. Поскольку действия по включению могут повторяться, полезно в состав методов класса добавить защищенную процедуру, включающую событие. Даже если событие зажигается только в одной точке, написание такой процедуры считается признаком хорошего стиля. Этой процедуре обычно дается имя, начинающееся со слова On, после которого следует имя события. Будем называть такую процедуру On-процедурой. Она проста и состоит из вызова объявленного события, включенного в тест, который проверяет перед вызовом, а есть ли хоть один обработчик события, способный принять соответствующее сообщение. Если таковых нет, то нечего включать событие. Приведу пример:

protected virtual void OnFire(int time, int build)

{

if (FireEvent!=null)

FireEvent(this,time, build);

}

Хочу

обратить внимание: те, кто принимает сообщение о событии, должны заранее присоединить обработчики событий к объекту FireEvent, задающему событие. Присоединение обработчиков должно предшествовать зажиганию события. При таком нормальном ходе вещей, найдется хотя бы один слушатель сообщения о событии — следовательно, FireEvent не будет равно null.

Заметьте также, что процедура On объявляется, как правило, с модификаторами protected virtual.

Это позволяет потомкам класса переопределить ее, когда, например, изменяется набор аргументов события.

Последний шаг, который необходимо выполнить в классе Sender — это в нужных методах класса вызвать процедуру On. Естественно, что перед вызовом нужно определить значения входных аргументов события. После вызова может быть выполнен анализ выходных аргументов, определенных обработчиками события. Чуть позже рассмотрим более полные примеры, где появится вызов процедуры On.

Классы receiver. Как обрабатываются события

Объекты класса Sender создают события и уведомляют о них объекты, возможно, разных классов, названных нами классами Receiver, или клиентами. Давайте разберемся, как должны быть устроены классы Receiver, чтобы вся эта схема заработала.

Понятно, что класс receiver должен:

• иметь обработчик события — процедуру, согласованную по сигнатуре с функциональным типом делегата, который задает событие;

• иметь ссылку на объект, создающий событие, чтобы получить доступ к этому событию — event-объекту;

• уметь присоединить обработчик события к event-объекту. Это можно реализовать по-разному, но технологично это делать непосредственно в конструкторе класса, так что когда создается объект, получающий сообщение, он изначально готов принимать и обрабатывать сообщения о событиях. Вот пример, демонстрирующий возможное решение проблем:

public class FireMen

{

private TownWithEvents MyNativeTown;

public FireMen(TownWithEvents TWE)

{

this.MyNativeTown=TWE;

MyNativeTown.FireEvent += new

FireEventHandler(FireHandler);

}

private void FireHandler(object Sender, int time, int build)

{

Console.WriteLine("Fire at day {0}, in build {1}!", time, build);

}

public void GoOutO

{

MyNativeTown.FireEvent — = new FireEventHandler(FireHandler);

}

}//FireMan

В классе Fireman есть ссылка на объект класса TownWithEvents, создающий события. Сам объект передается в конструкторе класса. Здесь же происходит присоединение обработчика события к event-объекту. Обработчик события FireHandler выводит сообщение на консоль.

Поделиться:
Популярные книги

Вечный. Книга I

Рокотов Алексей
1. Вечный
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга I

Попаданка в деле, или Ваш любимый доктор

Марей Соня
1. Попаданка в деле, или Ваш любимый доктор
Фантастика:
фэнтези
5.50
рейтинг книги
Попаданка в деле, или Ваш любимый доктор

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Жена проклятого некроманта

Рахманова Диана
Фантастика:
фэнтези
6.60
рейтинг книги
Жена проклятого некроманта

Третий. Том 2

INDIGO
2. Отпуск
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 2

Королева Солнца. Предтечи. Повелитель зверей. Кн. 1-17

Нортон Андрэ
Королева Солнца
Фантастика:
фэнтези
6.25
рейтинг книги
Королева Солнца. Предтечи. Повелитель зверей. Кн. 1-17

Опасная любовь командора

Муратова Ульяна
1. Проклятые луной
Фантастика:
фэнтези
5.00
рейтинг книги
Опасная любовь командора

Лютая

Шёпот Светлана Богдановна
Любовные романы:
любовно-фантастические романы
6.40
рейтинг книги
Лютая

Леди для короля. Оборотная сторона короны

Воронцова Александра
3. Королевская охота
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Леди для короля. Оборотная сторона короны

Светлая тьма. Советник

Шмаков Алексей Семенович
6. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Светлая тьма. Советник

Измена дракона. Развод неизбежен

Гераскина Екатерина
Фантастика:
городское фэнтези
фэнтези
5.00
рейтинг книги
Измена дракона. Развод неизбежен

Попаданка для Дракона, или Жена любой ценой

Герр Ольга
Любовные романы:
любовно-фантастические романы
7.17
рейтинг книги
Попаданка для Дракона, или Жена любой ценой

Адвокат империи

Карелин Сергей Витальевич
1. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
фэнтези
5.75
рейтинг книги
Адвокат империи

Измена. Избранная для дракона

Солт Елена
Любовные романы:
любовно-фантастические романы
3.40
рейтинг книги
Измена. Избранная для дракона