Г. Шилдт - Полный справочник по C# (1160789), страница 78
Текст из файла (страница 78)
Теперь перейдем к рассмотрению примеров.В следующей программе создается класс х, в котором в качестве обработчика событий определен метод экземпляра. Это значит, что для получения информации о событиях каждый объект класса X необходимо регистрировать отдельно. Для демонстрации этого факта программа готовит уведомление о событии для многоадресатной передачи трем обьектам типа X./* При использовании в качестве обработчиков событийметодов экземпляров уведомление о событиях принимаютотдельные объекты. */u s i n g System;Глава 15. Делегаты и события419// Объявляем делегат для события,delegate void MyEventHandler();// Объявляем класс события,class MyEvent {public event MyEventHandler SomeEvent;// Этот метод вызывается для генерирования события,public void OnSomeEvent() {if(SomeEvent != null)SomeEvent();class X {int id;чpublic X(int x) { id = x; }// Метод экземпляра, используемый в качестве// обработчика событий,public void Xhandler() {Console.WriteLine("Событие принято объектом " + id);class EventDemo {public static void Main() {MyEvent evt = new MyEvent();X ol = new X(l) ;X o2 = new X(2) ;X o3 = new X(3);evt.SomeEvent += new MyEventHandler(ol.Xhandler);evt.SomeEvent += new MyEventHandler(o2.Xhandler);evt.SomeEvent += new MyEventHandler(o3.Xhandler);// Генерируем событие,evt.OnSomeEvent() ;Результаты выполнения этой программы имеют такой вид:I Событие принято объектом 1I Событие принято объектом 21 Событие принято объектом 3Как подтверждают эти результаты, каждый объект заявляет о своей заинтересованности в событии и получает о нем отдельное уведомление.Если же в качестве обработчика событий используется статический метод, то, какпоказано в следующей программе, события обрабатываются независимо от объекта./* При использовании в качестве обработчиков событийстатического метода уведомление о событиях получаеткласс.
*/using System;// Объявляем делегат для события.420Часть I. Язык С#delegate void MyEventHandler();// Объявляем класс события,class MyEvent {public event MyEventHandler SomeEvent;// Этот метод вызывается для генерирования события,public void OnSomeEvent() {if(SomeEvent != null)SomeEvent();}class X {/* Это статический метод, используемый в качествеобработчика события. */public static void XhandlerO {Console.WriteLine("Событие получено классом.");class EventDemo {public static void Main() {MyEvent evt = new MyEvent();evt.SomeEvent += new MyEventHandler(X.Xhandler);// Генерируем событие,evt.OnSomeEvent();Вот как выглядят результаты выполнения программы:I Событие получено классом.Обратите внимание на то, что в программе не создается ни одного объекта типа х.Но поскольку h a n d l e r () — статический метод класса X, его можно связать с событием SomeEvent и обеспечить его выполнение при вызове метода OnSomeEvent ().Использование событийных средств доступаПредусмотрены две формы записи инструкций, связанных с событиями.
Форма,используемая в предыдущих примерах, обеспечивала создание событий, которые автоматически управляют списком вызова обработчиков, включая такие операции, какдобавление обработчиков в список и удаление их из списка. Таким образом, можнобыло не беспокоиться о реализации операций по управлению этим списком. Поэтомутакие типы событий, безусловно, являются наиболее применимыми. Однако можно исамим организовать ведение списка обработчиков событий, чтобы, например, реализовать специализированный механизм хранения событий.Чтобы управлять списком обработчиков событий, используйте вторую формуevent-инструкции, которая позволяет использовать средства доступа к событиям. Этисредства доступа дают возможность управлять реализацией списка обработчиков событий.
Упомянутая форма имеет следующий вид:event событийный_делегат имя__события {add{Глава 15. Делегаты и события421// Код добавления события в цепочку событий.remove {// Код удаления события из цепочки событий.}Эта форма включает два средства доступа к событиям: add и remove. Средстводоступа add вызывается в случае, когда с помощью оператора "+=" в цепочку событийдобавляется новый обработчик, а средство доступа remove вызывается, когда с помощью оператора " - = " из цепочки событий удаляется новый обработчик.Средство доступа add или remove при вызове получает обработчик, который необходимо добавить или удалить, в качестве параметра.
Этот параметр, как и в случае использования других средств доступа, называется value. При реализации средств доступа add и remove можно задать собственную схему хранения обработчиков событий.Например, для этого вы могли бы использовать массив, стек или очередь.Рассмотрим пример использования событийных средств доступа. Здесь для хранения обработчиков событий взят массив.
Поскольку этот массив содержит три элемента, в любой момент времени в событийной цепочке может храниться только три обработчика событий.// Создание собственных средств управления списком событий.using System;// Объявляем делегат для события,delegate void MyEventHandler();// Объявляем класс события для хранения трех// обработчиков событий,class MyEvent {MyEventHandler[] evnt = new MyEventHandler[3];public event MyEventHandler SomeEvent {// Добавляем обработчик события в список,add {int i ;for(i=0; i < 3;i f ( e v n t [ i ] == null) {evnt[i] - value;break;if}(i == 3)Console.WriteLine("Список обработчиков событий полон.");// Удаляем обработчик события из списка,remove {int i ;for(i=0; i < 3;if(evnt[i] == value)evnt[i] = null;break;422Часть I.
Язык C#if (i ~ 3)Console.WriteLine("Обработчик события не найден.");// Этот метод вызывается для генерирования событий,public void OnSomeEvent() {for(int i=0; i < 3; i++)if(evnt[i] !== null) evnt[i]();// Создаем классы, которые используют// делегат MyEventHandler.class W {public void WhandlerO {Console.WriteLine("Событие получено объектом W.")class X {public void XhandlerO {Console.WriteLine("Событие получено объектомX.");class Y {public void YhandlerO {Console.WriteLine("Событие получено объектом Y . " ) ;class Z {public void ZhandlerO {Console.WriteLine("Событие получено объектом Z.")class EventDemo {public static void MainO {MyEvent evt = new MyEvent();W wOb = new W();X xOb = new X();Y yOb = new Y () ;Z zOb = new Z () ;// Добавляем обработчики в список.Console.WriteLine("Добавление обработчиков событий.");evt.SomeEvent += new MyEventHandler(wOb.Whandler);evt.SomeEvent += new MyEventHandler(xOb.Xhandler);evt.SomeEvent += new MyEventHandler(yOb.Yhandler);// Этот обработчик сохранить нельзя — список полон,evt.SomeEvent += new MyEventHandler(zOb.Zhandler);Console.WriteLine();// Генерируем события.Глава 15.
Делегаты и события423evt.OnSomeEvent() ;Console.WriteLine() ;// Удаляем обработчик из списка.Console.WriteLine("Удаляем обработчик xOb.Xhandler.");evt.SomeEvent -= new MyEventHandler(xOb.Xhandler);evt.OnSomeEvent();Console.WriteLine() ;// Пытаемся удалить его еще раз.Console.WriteLine("Попытка повторно удалить обработчик xOb.Xhandler.");evt.SomeEvent -= new MyEventHandler(xOb.Xhandler);evt.OnSomeEvent();Console.WriteLine();// Теперь добавляем обработчик Zhandler.Console.WriteLine("Добавляем обработчик zOb.Zhandler.")evt. SomeEvent += new MyEventHandler (zOb. Z*handler) ;evt.OnSomeEvent();Вот результаты выполнения программы:Добавление обработчиков событий.Список обработчиков событий полон.Событие получено объектом W.Событие получено объектом X.Событие получено объектом Y.Удаляем обработчик xOb.Xhandler.Событие получено объектом W.Событие получено объектом Y.Попытка повторно удалить обработчик xOb.Xhandler.Обработчик события не найден.Событие получено объектом W.Событие получено объектом Y.Добавляем обработчик zOb.Zhandler.Событие получено объектом W.Событие получено объектом Z.Событие получено объектом Y.Рассмотрим внимательно код этой программы.
Сначала определяется делегат обработчика события MyEventHandler. Код класса MyEvent, как показано в следующейинструкции, начинается с определения трехэлементного массива обработчиков событий evnt.I MyEventHandler[] evnt = new MyEventHandler[3];Этот массив предназначен для хранения обработчиков событий, которые добавлены в цепочку событий. Элементы массива evnt инициализируются null-значениямипо умолчанию.Приведем event-инструкцию, в которой используются событийные средства доступа.424Часть I. Язык С#public event MyEventHandler SomeEvent {// Добавляем обработчик события в список,add {int i ;for(i=0; i < 3;if(evnt[i] == null) {evnt[ij = value;break;if}(i == 3)^Console.WriteLine("Список обработчиков событий полон.");// Удаляем обработчик события из списка,remove {int i;for(i=0; i < 3; iif(evnt[i] == value) {evnt[i] = null;break;}if (i == 3)Console.WriteLine("Обработчик события не найден.");При добавлении в список обработчика событий вызывается add-средство, и ссылкана этот обработчик (содержащаяся в параметре value) помещается в первый встретившийся неиспользуемый элемент массива evnt.
Если свободных элементов нет,выдается сообщение об ошибке. Поскольку массив evnt рассчитан на хранение лишьтрех элементов, он может принять только три обработчика событий. При удалениизаданного обработчика событий вызывается remove-средство, и в массиве evnt выполняется поиск ссылки на обработчик, переданной в параметре value.
Если ссылканайдена, в соответствующий элемент массива помещается значение n u l l , что равнозначно удалению обработчика из списка.При генерировании события вызывается метод OnSomeEvent (). Он в цикле просматривает массив evnt, по очереди вызывая каждый обработчик событий.Как показано в предыдущих примерах, при необходимости относительно нетруднореализовать собственный механизм хранения обработчиков событий. Для большинства приложений все же лучше использовать стандартный механизм хранения, в котором не используются событийные средства доступа.
Однако в определенных ситуациях форма event-инструкции, ориентированной на событийные средства доступа, может оказаться весьма полезной. Например, если в программе обработчики событийдолжны выполняться в порядке уменьшения приоритетов, а не в порядке их добавления в событийную цепочку, то для хранения таких обработчиков можно использоватьочередь по приоритету.Смешанные средства обработки событийСобытия можно определять в интерфейсах. "Поставкой" событий должны заниматься соответствующие классы.