Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 94
Текст из файла (страница 94)
Как демонстрирует рассматриваемый здесь пример программы, механизм хранения обработчиков событий нетрудно реализовать, если в этом есть потребность. Но для боль- 488 часть (. язык сз шинства приложений более подходящим оказывается используемый по умолчанию механизм хранения обработчиков событий, который обеспечивает форма оператора ечепс без аксессоров. Тем не менее аксессорная форма оператора ечепс оказывается пригодной в ряде особых случаев. Так, если обработчики событий необходимо выполнять в программе в порядке их приоритетности, а не в том порядке, в каком они вводятся в цепочку событий, то для их хранения можно воспользоваться очередью по приоритету.
На эатеткуу В многолоточнык приложениял обьтно лрикодится синхронизировать доспи/л к аксессорам событий Подробнее о многопоточном программировании речь дойдет в главе 23. Разнообразные возможности событий События могут быть определены и в интерфейсах. При этом события должны предоставляться классами, реализующими интерфейсы. События могут быть также определены как абстрактные (аЬзг та с с). В этом случае конкретное событие должно быть реализовано в производном классе. Но аксессорные формы событий не могут быль абстрактными.
Кроме того, событие может быть определено как герметичное гзев1еб). И наконец, событие может быть виртуальным, т.е. его можно переопределить в производном классе. Применение анонимных методов и лямбда- выражений вместе с событиями Анонимные методы и лямбда-выражения особенно удобны для работы с событиями, поскольку обработчик событий зачастую вызывается только в коде, реализующем механизм обработки событий.
Это означает, что создавать автономный метод, как правило, нет никаких причин. А с помощью лямбда-выражений или анонимных методов можно существенно упростить код обработки событий. Как упоминалось выше, лямбда-выражениям теперь отдается большее предпочтение по сравнению с анонимными методами, поэтому начнем именно с них. Ниже приведен пример программы, в которой лямбда-выражение используется в качестве обработчика событий. Л Использовать ляыбда-выражение в качестве // обработчика событий. пв1пд Бувсеьп // Объявить тип делегата для события.
бе1едаге чо1б МуЕчепгиаоб1ег(упг о)г // Объявить класс, содержащий событие. с1авв МуЕчепг ( риЬ11с ечепг МуЕчепгнапб1ег БовеЕчепгг // Этот метод вызывается для запуска события. рчнугс чоьб Опзовевчепг(1пг п) ( 11(зовеЕчепг (= пч11) Бовеечепс(п)г с1авв Ьавббакчепгпево ( Глава (б. Делегаты, события и ляыбда-выражения 489 лгзС1с чо1б Маго() ( МуЕнеоС ечС = пен МуЕнепС (); // Использовать ллыбда-зыражение в О качестве обработчика событий.
енл.эовеЕнеоС += (о) => соозо1е.иг1сеьяпе("событие получено. значение равно " + п) // Запустить событие. ечС.ОоэовеЕнепС(1)т енС.Оо5овеЕчеоС (2) т ) ) Вот к какому результату приводит выполнение этой программы: Событие получено. Значение равно 1 Событие получено. Значение равно 2 Обратите особое внимание иа то, как и этой программе лямбла-выражение используется в качестве обработчика событий: ечС.5овеЕнеоС += (о) => Сооло1е . Игхсеъхое (" Событие получено . Значение равно " + о) т Синтаксис для использования лямбда-выражеиия в качестве обработчика событий остается таким же, как для его применения вместе с любым другим типом делегата.
Несмотря иа то что при создании анонимной функции предпочтение следует теперь отдавать лямбда-выражениям, в качестве обработчика событий можно по-прежнему использовать анонимный метод. Ниже приведен вариант обработчика событий из предыдущего примера, переделаииый с целью продемонстрировать применение аиоиимиого метода. // Использовать анонимный метод в качестве // обработчика событий. ене.эовепнепС += бе1едасе(1пс и) ( Сооео1е.пг1Сетеое("Событие получено.
Значение равно " + о)т )' Как видите, синтаксис использования анонимного метода в качестве обработчика событий остается таким же, как и для его применения вместе с.любым другим типом делегата. Рекомендации по обработке событий в среде . НЕТ ГгатеччогМ В языке С() разрешается формировать какие угодно разновидности событий. Но ради совместимости программных компонентов со средой .НЕТ Егащетчог(( следует придерживаться рекомендаций, установленных для этой цели корпорацией М(сгоэо(С.
Эти рекомеидации, по существу, сводятся к следующему требованию: у обработчиков событий должны быть два параметра. Первый из иих — ссылка иа объект, формирующий собьпие, второй — параметр типа ЕчепСйгдэ, содержащий любую дополнительную информацию о событии, которая требуется обработчику. Таким образом, .НЕТ-совместимые обработчики событий должны иметь следующую общую форму: 490 часть). язык С» чо1С обработчик(оп)есг источник, Ечепгйгдя агд) ( // ...
) Как правило, источник — зто параметр, передаваемый вызывающим кодом с помощью ключевого слова гЬ15. А параметр типа Ечепгйгдв содержит дополнительную информацию О событии и может быть проигнорирован, если он не нужен. Сам класс ечепгйгдв не содержит поля, которые могут быть использованы для передачи дополнительных данных обработчику. напротив, ечепгйгдя служит в качестве базового класса, от которого получается производный класс, содержащий все необходимые поля.
Тем не менее в классе ечепсйгдя имеется одно поле ещргу типа ягаг1с, которое представляет собой объект типа ечепгйгдя без данных. Ниже приведен пример программы, в которой формируется .)ь)ЕТ-совместимое событие. // Пример формирования .НЕТ-совместимого события. пятпд 5увсещ; // Объявить класс, производный от класса БчепСйгдв. с1авв Муачепгйгдв: Ечепгйгдв ( рпЫьс 1пг Ечепгипщк ) // Объявить тип делегата для события. Се1едаге чо1С МуЕчепСНапб1ег(оЬ)есг вопгсе, МуЕчепгйгдв агд) // Объявит~ класс, содержащий событие. с1авв МуЕчепг ( ягагъс ъпг соппг = О; рпЫ1с ечепс муечепснапб1ег Яощеечепс; // этот метод запускает событие Яощеечепс. рпЬ11с чогб ОпЯощеЕчепг() ( МуЕчепгйгдя агд = печ МуЕчепгйгдя(); 11(зощеЕчепг != пп11) ( агд.ечепснпщ = соппс+ь) 5ощекчепг(СЫв, агд); ) ) ) с1авя Х ( рпЫъс чогб Напб1ег(обзесг вопгсе, МуЕчепгйгдв агд) ( Сопяо1е.Игпгег1пе("Событие " + агд.Ечепгипщ т " получено объектом клааса Х."); Сопво1е.игьгег1пе("Источник: " + воигсе); Сопяо1е.иг1геаппе(); ! ) с1аяв у ( рпЬ11с чогб Напб1ег(оозесг яопгсе, МуЕчепгйгдя агд) ( Сопво1е.Иг1сегапе("Событие " ь агд.вчепгипщ ь " получено объектом класса у.")) Глава 15.
Делегаты, события и ллыбдв.вырвжеиил 491 сопяо1е.иггсеътпе("источник: " + яоцтсе) т Сопяо1е. Нг1еет Епе () т ) с1яяя Ечепепевоб ( ясяс1с човб Малп() ( Х овт пен Х() т т оЬ2 = пеи у() т МуЕчепе ече = пен МуЕчепе()т // Добавить обработчик Напб1ег() в цепочку событий. ечс.яовеечепс += оь1.напб1егт ече.зовевчепс += оЬ2.папб1егт // Запустить событие. ече.опзовевчепе О ! ече .ОпзовеЕчепе () т ) Ниже приведен результат выполнения этой программы. Событие О получено объектом класса Х Источник: Мувчяпе Событие О получено объектом класса У Источник: Мувчепе Событие 1 получено объектом класса Х Источник: МуЕчепС Событие 1 получено объектом класса У Источник: Мувчепе В данном примере создается класс муечепы(гоз, производный от класса ечепьлгоя. В классе мупчепслгоз добавляется лишь одно его собственное поле: Ечепснпв.
Затем объявляется делегат муечепснапс(1ег, принимаюп(ий два параметра, требующиеся для среды .ХЕТ Егашечгог((. Как пояснялось выше, первый параметр содержит ссылку на обьект, формирующий событие, а второй параметр — ссылку на объект класса ечепьлгоз или производного от него класса Обработчики событий Напг(1ег (), определяемые в классах х и т, принимают параметры тех же самых типов.
В классе муечепс объявляется событие еовеечепс типа муечепснапг(1ег. Это событие запускается в методе Опяовеечепс () с помощью делегата Бовеечепс, которому в качестве первого аргумента передается ссылка ЕЬ1з, а вторым аргументом служит экземпляр объекта типа МуЕчептдгоз. Таким образом, делегату типа Мупчепенапс)1ег передаются надлежащие аргументы в соответствии с требованиями совместимости со средой .)ь(ЕТ. Применение встроенного делегата Ечее1~Нае1й1ег Для обработки многих событий параметр типа Ечепе))гдз оказывается ненужным.