Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 92
Текст из файла (страница 92)
И в заключение рассмотрим еще один пример, демонстрирующий блочное лямбдавыражение в действии. Ниже приведен вариант первого примера из этой главы, переделаииого с целью использовать блочные лямбда-выражения вместо автономных методов для выполнения различных операций со строками. // Первый пример применения делегатов, переделанный с // целью испольэовать блочные лямбда-выражения. цэгпд Яуэсею) // Объявить тип делегата. бе1едаге эгггпд Яггмоб(вСггпд в); с1авв Овезгагеюепгьаю)тбаэ ( вгагтс чо1б Маго() ( // Создать делегаты, ссылающиеся на // лямбда- выражения, выполняющие различные Глава !5.
Делегаты, события и лямбда.выражения 477 // операции со строками. // Заменить пробелы дефисами. яттиоб Нер1асеярасев = в => ( сопяо1е.итлтеьтпе("Замена пробелов дефисами.") тетцтп в.аер1асе(' ', '-')т )/ // Удалить пробелы. Яттмоб Невотеярасев = в => ( встгпс севр = ""; тпт т) Сопво1е.ытттетлпе("Удаление пробелов."); тот(1=0) т < з.ьепдтп) т++) 1т (в ( 1) ! = ' ') севр += в [) ) т теьцтп тевр) )т // Обратить строку. Яттмоб Нечетве = з => ( вст1по севр = "' Ьпс )., Э) Сопзо1е.Ит1теЬтпе("Обращение строки."); тот(1=0, в=в.Ьепдти-1) 1 >= О) >†, фт+) тевр т= в[1)) тетцтп теврг )) втт1по вст) // Обратиться к лямбда-выражениям с помощью // делегатов. Яттиоб автор = Нер1асеЯрасевт вот = астор("Это простой тест."); Сопво1е.Итттевлпе("Результирующая строка: " т зтт) Сопво1е.ыт1теЬ1пе()) астор = ВевотеЯрасев) вст = астор("это простой тест."); Сопво1е.нтттеЬтпе("Результирующая строка: " Ь зтт) Сопво1е.ытттеЬ1пе()) астор = Вететвет вот = автор("Это простой тест."); сопво1е.иттсеьгпе("Результирующая строка: " + вст)) ) ) Результат выполнения кода этого примера оказывается таким же, как и в первом примере применения делегатов: 478 Часть ).
язык Сэ Замена пробелов дефисами. Результирующая строка: Это-простой-тест. Удаление пробелов. Результирующая строка: Этопростойтест. Обращение строки. Результирующая строка: .тсет йотсорп отЭ События Еще одним важным средством СФ, основывающимся на делегатах, является собылтие. Событие, по существу, представляет собой автоматическое уведомление о том, что произошло некоторое действие.
События действуют по следующему принципу: объект, проявляющий интерес к событию, регистрирует обработчик этого события. Когда же событие происходит, вызываются все зарегистрированные обработчики этого события. Обработчики событий обычно представлены делегатами. События являются членами класса и объявляются с помощью ключевого слова ечепс. Чаше всего для этой цели используется следующая форма: ечепк делегат события ямя события; где делегат события обозначает имя делегата, используемого для поддержки события, а иыя события — конкретный объект объявляемого события. Рассмотрим для начала очень простой пример: // Очень простой пример, демонстрирующий событие. паапа Бузсегю // Объявить тип делегата для события. бе1еоасе чотб МуЕчепСНапб1ег()т // Объявить класс, содержащий событие.
с1ааз МуЕчепк ( рпЫ1с ечепк МУЕчепкнапб1ег ЯошеЕчепкт // Этот метод вызывается для запуска события. роЫъс чоюб Опзошевчепк() ( 1Г(БошеЕчепо != пп11) БошеЕчепк()т ) ) с1авз Ечепкоеюо ( // Обработчик события. зкак1с чоъб Напб1ег() ( Сопзо1е.нг1сетапе("Произошло событие") ) зкаС1с чо1б Мако() ( МУЕчепк ечк = пеи МУЕчепк() // Добавить метод Напб1ег() в список событий. ечк.зошевчепк т= Напб1ею Глава! б. Делегаты, события и ляыбдв-выражения 479 // Запустить событие. ечп.опЯовеЕчепв()т ) Вот какой результат получается при выполнении этого кода: Произошло событие Несмотря на всю свою простоту, данный пример кода содержит все основные элементы, необходимые для обработки событий. Он начинается с объявления типа делегата для обработчика событий, как показано ниже.
г(е1едаве чо1б МуЕчепСНапб1ег()т Все события активизируются с помощью делегатов. Поэтому тип делегата события определяет возвращаемый тип и сигнатуру для события. В данном случае параметры события отсутствуют, но их разрешается указывать. Далее создается класс события муечепс. В этом классе объявляется событие Бовекчепт в следующей строке кода: риъ11с ечепв Мукчептнапс(1ег БовеЕчеппт Обратите внимание на синтаксис этого объявления. Ключевое слово ечепс уведомляет компилятор о том, что объявляется событие.
Кроме того, в классе муечепс объявляется метод опяовеечепс (), вызываемый для сигнализации о запуске события. Это означает, что он вызывается, когда происходит событие. В методе опяовеечепс () вызывается обработчик событий с помощью делегата ЯовеЕчептя 1Г(зовекчепв (= пп11) ЯовеЕчепп()Г Как видите, обработчик вызывается лишь в том случае, если событие Бовеечеп с не является пустым. А поскольку интерес к событию должен быть зарегистрирован в других частях программы, чтобы получать уведомления о нем, то метод опБовеечепс () может быть вызван до регистрации любого обработчика события.
Но во избежание вызова по пустой ссылке делегат события должен быть проверен, чтобы убедиться в том, что он не является пустым. В классе Ечепспево создается обработчик событий напс(1ег () . В данном простом примере обработчик событий просто выводит сообщение, но другие обработчики могут выполнять более содержательные функции. Далее в методе ма1п () создается объект класса события муечепс, а напс(1ег () регистрируется как обработчик этого события, добавляемый в список.
МуЕчепп ечп = пеи МуЕчепп()т // добавить метод напб1ег() з список событий. ечт.зовекчепг Е= Напб1егг Обратите внимание на то, что обработчик добавляется в список с помощью оператора т=. События поддерживают только операторы += и -=. В данном случае метод Напс(1ег () является статическим, но в качестве обработчиков событий могут также служить методы экземпляра. И наконец, событие запускается, как показано ниже. // Запустить событие.
ечт.опзовеЕчепт()Г 480 Часть ). язык Сз Вызов метода Опзощеечепс () приводит к вызову всех событий, зарегистрированных обработчиком. В данном случае зарегистрирован только один такой обработчик, но их может быть больше, как поясняется в следующем разделе. Пример групповой адресации события Как и делегаты, события поддерживают групповую адресацию. Это дает возможность нескольким объектам реагировать на уведомление о событии. Ниже приведен пример групповой адресации события. // Продемокстрировать групповую адресацию события, ця1пд Яуясещт // Объявить тип делегата для события. бе1еЧаке чоЫ Мунчептнапб1ег()г // Объявить делегат, содержащий событие.
с1аяя МуЕчепк ( рцн11с ечепк Мунчепонапб1ег ЯощеЕчепк/ // Этот метод вызывается для запуска события. рцЬ11с чотб ОпзощеЕчепк() ( ьв(зоюехчепк (= пц11) ЯощеЕчепс()/ ) ) с1аяя Х ( рцбттс чозб Хпапб1ег() ( Сопяо1е.нгхкеъхпе("Событие получено объектом класса Х"); ) с1аяя т ( рцЬ11с чотб Унапб1ег() ( Сопяо1е.игткевапе("Событие получено объектом класса у"); ) с1аяя Ечепкоещо2 ( якаотс чо1б Напб1ег() ( Сопяо1е.игхкеътпе("Событие получено объектом класса Ечепвпещо") ) якая1с чозд Ма1п() ( МуЕчепп ечо = пен Мунчепт() Х хОЬ = пен Х()/ У уОЬ = пен У(); // добавить обработчики в список событий.
ечг.зощехчепк += Напб1еш ечС.Яощенчепк т= хОЬ.ХПапб1ег/ ечк.зощенчепк += уОЬ.УЬапб1ег/ Глава 15. Делегаты, события н ляыбда-еыраження 481 // Запустить событие. ечс.бпзовекчепв()л Сопво1е.иг1сеьепе О г // Удалить обработчик. ечо.зовекчепо =- хбб.хпапб1ег/ ечг.бпзовекчепг()) При выполнении кода этого примера получается следующий результат: Событие получено объектом класса Ечепгоево Событие получено объектом класса Х Событие получено объектом класса т Событие получено объектом класса Ечепопево Собитие ПоЛучЕно объектом класса т В данном примере создаются два дополнительных класса, х и у, в которых также определяются обработчики событий, совместимые с делегатом муечепснапп1ег. Поэтому эти обработчики могут быть также включены в цепочку событий.
Обратите внимание на то, что обработчики в классах х и у не являются статическими. Это означает, что сначала должны быть созданы объекты каждого из этих классов, а затем в цепочку событий должны быть введены обработчики, связанные с их экземплярами. Об отличиях между обработчиками экземпляра и статическими обработчиками речь пойдет в следующем разделе. Методы экземпляра в сравнении со статическими методами в качестве обработчиков событий Методы экземпляра и статические методы могут быть использованы в качестве обработчиков событий, но между ними имеется одно существенное отличие.
Когда статический метод используется в'качестве обработчика, уведомление о событии распространяется на весь класс. А когда в качестве обработчика используется метод экземпляра, то события адресуются конкретным экземплярам объектов. Следовательно, кюкдый объект определенного класса, которому требуется получить уведомление о событии, должен быть зарегистрирован отдельно. На практике большинство обработчиков событий представляют собой методы экземпляра, хотя это, конечно, зависит от конкретного приложения. Рассмотрим применение каждой из этих двух разновидностей методов в качестве обработчиков событий на конкретных примерах. В приведенной ниже программе создается класс Х, в котором метод экземпляра определяется в качестве обработчика событий.
Это означает, что каждый объект класса х должен быть зарегистрирован отдельно, чтобы получать уведомления о событиях. Для демонстрации этого факта в данной программе производится групповая адресация события трем отдельным объектам класса х. /* Уведомления о событиях получают отдельные объекты, когда метод Экземпляра используется в качестве обработчика событий. */ пвлпо Яувоекч 482 Часть ). Язык С» // Объявить тип делегата для события.