1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 77
Текст из файла (страница 77)
Вэтом случае на одно уведомление о событии может отвечать несколько объектов.Рассмотрим пример.// Демонстрация использования события, предназначенного// для многоадресатной передачи.using System;// Объявляем делегат для события.delegate void MyEventHandler();// Объявляем класс события.class MyEvent {public event MyEventHandler SomeEvent;}// Этот метод вызывается для генерирования события.public void OnSomeEvent() {if(SomeEvent != null) SomeEvent();}class X {public void Xhandler() {Console.WriteLine("Событие, полученное объектом X.");}}class Y {public void Yhandler() {Console.WriteLine("Событие, полученное объектом Y.");}}class EventDemo {static void handler() {Console.WriteLine("Событие, полученное классом EventDemo.");}public staticMyEvent evtX xOb = newY yOb = new418void Main() {= new MyEvent();X();Y();Часть I.
Язык C#// Добавляем обработчики в список события.evt.SomeEvent += new MyEventHandler(handler);evt.SomeEvent += new MyEventHandler(xOb.Xhandler);evt.SomeEvent += new MyEventHandler(yOb.Yhandler);// Генерируем событие. evt.OnSomeEvent();Console.WriteLine();}}// Удаляем один обработчик.evt.SomeEvent -= new MyEventHandler(xOb.Xhandler);evt.OnSomeEvent();Результаты выполнения этой программы имеют следующий вид:Событие, полученное классом EventDemo.Событие, полученное объектом X.Событие, полученное объектом Y.Событие, полученное классом EventDemo.Событие, полученное объектом Y.В этом примере создается два дополнительных класса X и Y, в которых такжеопределяютсяобработчикисобытий,совместимыессигнатуройделегатаMyEventHandler.
Следовательно, эти обработчики могут стать частью цепочкисобытийных вызовов. Обратите внимание на то, что обработчики в классах X и y неявляются статическими. Это значит, что сначала должны быть созданы объекты каждогокласса, после чего в цепочку событийных вызовов должен быть добавлен обработчик,связанный с каждым экземпляром класса. Различие между статическими обработчиками иобработчиками экземпляров классов рассматривается в следующем разделе.Сравнение методов экземпляров классов со статическими методами,используемыми в качестве обработчиков событийНесмотря на то что и методы экземпляров классов, и статические методы могутслужить обработчиками событий, в их использовании в этом качестве есть существенныеразличия. Если в качестве обработчика используется статический метод, уведомление особытии применяется к классу (и неявно ко всем объектам этого класса).
Если же в качествеобработчика событий используется метод экземпляра класса, события посылаются кконкретным экземплярам этого класса. Следовательно, каждый объект класса, которыйдолжен получать уведомление о событии, необходимо регистрировать в отдельности. Напрактике в большинстве случаев “роль” обработчиков событий “играют” методыэкземпляров классов, но, безусловно, все зависит от конкретной ситуации.
Теперь перейдемк рассмотрению примеров.В следующей программе создается класс X, в котором в качестве обработчикасобытий определен метод экземпляра. Это значит, что для получения информации особытиях каждый объект класса X необходимо регистрировать отдельно. Для демонстрацииэтого факта программа готовит уведомление о событии для многоадресатной передачи тремобъектам типа X./* При использовании в качестве обработчиков событийметодов экземпляров уведомление о событиях принимаютотдельные объекты. */using 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 o1 = new X(1);X o2 = new X(2);X o3 = new X(3);}}evt.SomeEvent += new MyEventHandler(o1.Xhandler);evt.SomeEvent += new MyEventHandler(o2.Xhandler);evt.SomeEvent += new MyEventHandler(o3.Xhandler);// Генерируем событие.evt.OnSomeEvent();Результаты выполнения этой программы имеют такой вид:Событие принято объектом 1Событие принято объектом 2Событие принято объектом 3Как подтверждают эти результаты, каждый объект заявляет о своейзаинтересованности в событии и получает о нем отдельное уведомление.Если же в качестве обработчика событий используется статический метод, то, какпоказано в следующей программе, события обрабатываются независимо от объекта./* При использовании в качестве обработчиков событий статическогометода уведомление о событиях получаеткласс.
*/using System;// Объявляем делегат для события.420Часть I. Язык C#delegate void MyEventHandler();// Объявляем класс события.class MyEvent {public event MyEventHandler SomeEvent;}// Этот метод вызывается для генерирования события.public void OnSomeEvent() {if(SomeEvent != null) SomeEvent();}class X {/* Это статический метод, используемый в качествеобработчика события. */}public static void Xhandler() {Console. WriteLine("Событие получено классом.");}class EventDemo {public static void Main() {MyEvent evt = new MyEvent();evt.SomeEvent += new MyEventHandler(X.Xhandler);}}// Генерируем событие.evt.OnSomeEvent();Вот как выглядят результаты выполнения программы:Событие получено классом.Обратите внимание на то, что в программе не создается ни одного объекта типа X.
Нопоскольку handler() — статический метод класса 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++)if(evnt[i] == null) {evnt[i] = value;break;}if(i == 3)Console.WriteLine("Список обработчиков событий полон.");}// Удаляем обработчик события из списка.remove {int i;for(i=0; i < 3; i++)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 Whandler() {Console.WriteLine("Событие получено объектом W.");}}class X {public void Xhandler() {Console.WriteLine("Событие получено объектом X.");}}class Y {public void Yhandler() {Console.WriteLine("Событие получено объектом Y.");}}class Z {public void Zhandler() {Console.WriteLine("Событие получено объектом Z.");}}class EventDemo {public static void Main() {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. Zhandler);evt.OnSomeEvent();Вот результаты выполнения программы:Добавление обработчиков событий.Список обработчиков событий полон.Событие получено объектом W.Событие получено объектом X.Событие получено объектом Y.Удаляем обработчик xOb.Xhandler.Событие получено объектом W.Событие получено объектом Y.Попытка повторно удалить обработчик xOb.Xhandler.Обработчик события не найден.Событие получено объектом W.Событие получено объектом Y.Добавляем обработчик zOb.Zhandler.Событие получено объектом W.Событие получено объектом Z.Событие получено объектом Y.Рассмотрим внимательно код этой программы.