Г. Шилдт - С#4.0 Полное руководство (1160795), страница 92
Текст из файла (страница 92)
Во-первых, как упоминалось ранее в этой главе, делегаты поддерживают события. И во-вторых, делегаты позволяют вызывать методы во время выполнения программы, не зная о них ничего определенного в ходе компиляции. Это очень удобно для создания базовой конструкции, допускающей подключение отдельных программных компонентов. Рассмотрим в качестве примера графическую программу, аналогичную стандартной сервисной программе Хшдотчв Рашк С помощью делегата можно предоставить пользователю возможность подключать специальные цветные фильтры или анализаторы изображений.
Кроме того, пользователь может составлять из этих фильтров или анализаторов целые последовательности. Подобные возможности программы нетрудно обеспечить, используя делегаты. Анонимные функции Метод, на который ссылается делегат, нередко используется только для этой цели. Иными словами, единственным основанием для существования метода служит то обстоятельство, что он может быть вызван посредством делегата, но сам он не вызывается вообще. В подобных случаях можно воспользоваться анонизгнои функцией, чтобы не создавать отдельный метод. Анонимная функция, по существу, представляет собой безымянный кодовый блок, передаваемый конструктору делегата.
Преимущество анонимной функции состоит, в частности, в ее простоте. Благодаря ей отпадает необходимость объявлять отдельный метод, единственное назначение которого состоит в том, что он передается делегату. Начиная с версии 3.0, в СФ предусмотрены две разновидности анонимных функций: анонимные методы и лямбда-выражения. Анонимные методы были внедрены в СФ еще в версии 2.0, а лямбда-выражения — в версии 3.0. В целом лямбда-выражение совершенствует принцип действия анонимного метода и в настоящее время считается более предпочтительным для создания анонимной функции. Но анонимные методы широко применяются в существующем коде СФ и поэтому по-прежнему являются важной составной частью СФ.
А поскольку анонимные методы предшествовали появлению лямбда-выражений, то ясное представление о них позволяет лучше понять особенности лямбда-выражений. К тому же анонимные методы могут быть использованы в целом ряде случаев, где применение лямбда-выражений оказывается невозможным. Именно поэтому в этой главе рассматриваются и анонимные методы, и лямбдавыражения. 484 Часть!. Язык С() Анонимные методы Анонимный метод — один из способов создания безымянного блока кода, связанного с конкретным экземпляром делегата.
Для создания анонимного метода достаточно указать кодовый блок после ключевого слова с)е1еоасе. Покажем, как это делается, на конкретном примере. В приведенной ниже программе анонимный метод служит для подсчета от О до 5. Продемонстрировать применение анонимного метода.
ивьлд зувсеиг // Объявить тип делегата. бе1едате тоьб Сонлт1С(); с1авв Влопнетлпето всасьс чоьб нагл() ( О Палее следует код для подсчета чисел, передаваемый делегату // в качестве анонимного метода. Сонлгтт соилг = бе1едате ( Этот кодовый блок передается делегату. Гог(ьлс ь=с; 1 <= 5/ 1++) Солво1е.нгьгевьое(1); )! // обратите внимание на точку с запятой соилс(); ) ) В данной программе сначала объявляется тип делегата Соипб1С без параметров и с возвращаемым типом чотб. Далее в методе Маап () создается экземпляр сонлг делегата СоинС1С, которому передается кодовый блок, следующий после ключевого слова бе1еггасе. Именно этот кодовый блок и являетсв анонимным методом, который будет выполняться при обращении к делегату сонлс.
Обратите внимание на то, что после кодового блока следует точка с запятой, фактически завершающая оператор объявления. Ниже приведен результат выполнения данной программы. Передача аргументов анонимному методу Анонимному методу можно передать один или несколько аргументов. Для этого достаточно указать в скобках список параметров после ключевого слова бе1еоасе, а при обращении к экземпляру делегата — передать ему соответствующие аргументы. В качестве примера ниже приведен вариант предыдущей программы, измененный с целью передать в качестве аргумента конечное значение для подсчета. Глава 15. Делегаты, события и лямбда-выражения 488 // Продемонстрировать применение анонимного метода, принимающего аргумент. свтпч Зувсещ; // Обратите внимание на то, что теперь у делегата Соппс1с имеется параметр.
Се1ечапв чо1б Соппс1с(ьпп епс); с1авв Лпопиеппбещо2 ( всасьс чотб На1п() Здесь конечное значение дпя подсчета передается анонимному методу. Соппп1С соипп = с(е1есасе (1пп епб) ( Гог(ьпп 1=0) 1 <= епб; 1++) сопво1е.нг1сеъ1пе(1); соспс (3); Сопво1е.игтпеьтпе(); сонпв(5); В этом варианте программы делегат СоппС1С принимает целочисленный аргумент. Обратите внимание на то, что при создании анонимного метода список параметров указывается после ключевого слова с(е1едабе. Параметр епс( становится доступным для кода в анонимном методе таким же образом, как и при создании именованного метода.
Ниже приведен результат выполнения данной программы. Возврат значения из анонимного метода Анонимный метод может возвращать значение. Для этой цели служит оператор гесс сп, действующий в анонимном методе таким же образом, как и в именованном методе. Как и следовало ожидать, тип возвращаемого значения должен быть совместим с возвращаемым типом, указываемым в объявлении делегата.
В качестве примера ниже приведен код, выполняющий подсчет с суммированием и возвращающий результат. // продемонстрировать применение анонимного метода, возвращающего значение. свгпд Яувсещ; 486 Часть Х язык С() // Этот делегат возврашает значение. с)е1едасе ьпг Соппг1С (1пс епо) г с1аяя АпопМесноеиоЗ яваг1С чс1о Ма1п() ( 1пг геяп1гг // Здесь конечное значение для подсчета передается анонимному методу. /У А возвращается сумма подсчитанных чисел. Соопг1С соппг = Ое1едасе (ьпг епг)) ( гпг япи = Ог Гог(ьпс 1=0; 1 <= епо; 1++) ( Сопяо1е.игггеьгпе(1); япи е= 1' ) гегпгп япзз // возвратить значение из анонимного метода геяп1Г = соопс (3); Сопяо1е.нг1се11пе("Сумма 3 равна " + геяо1г) Сопяо1е.игьсевьпе()г геяо1Г = соопс(5); Сопяо1е.нггсеьгпе("Сумма 5 равна " + геяп1Г); В этом варианте кода суммарное значение возвращается кодовым блоком, связанным с экземпляром делегата соппс.
Обратите внимание на то, что оператор геспгп применяется в анонимном методе таким же образом, как и в именованном методе. Ниже приведен результат выполнения данного кода. О 1 2 3 Суыма 3 равна б О 1 2 3 в 5 Сумма 5 равна 15 Применение внешних переменных в анонимных методах Локальная переменная, в область действия которой входит анониьгный метод, называется внешней переменной. Такие переменные доступны для использования в анонимном методе. И в этом случае внешняя переменная считается захваченной.
Захваченная переменная существует до тех пор, пока захвативший ее делегат не будет собран Глава 1б. Делегаты, события и лямбда-выражения 487 в "мусор". Поэтому если локальная переменная, которая обычно прекращает свое существование после выхода из кодового блока, используется в анонимном методе, то она продолжает существовать до тех пор, пока не будет уничтожен делегат, ссылающийся на этот метод. Захват локальной переменной может привести к неожиданным результатам.
В качестве примера рассмотрим еще один вариант программы подсчета с суммированием чисел. В данном варианте объект Соп пг1С конструируется и возвращается статическим методом сопл се г () . Этот объект использует переменную з пяь объявленную в охватывающей области действия метода Соппгег (), а не самого анонимного метода. Поэтому переменная зпщ захватывается анонимным методом. Метод соппсег () вызывается в методе маьп () для получения объекта соппс1с, а следовательно, переменная зпщ не уничтожается до самого конца программы. Продемонстрировать применение захваченной переменной.
иалпс Зувсещ; // этот делегат возвращает значение типа гпг и принимает аргумент типа ьпг. ое1ечаге 1пг соппт1г (ъпг епг(); с1ава Чагсаргпге ( всаг1с СоопСХС Сооптег() ( ъпг вощ = О; // Здесь подсчитанная сумма сохраняется в переменной вшп. Соопгтс сГОЬ3 = с(е1еоасе (1пс епй) Гог(гпг 1=0; 1 <= епс() 1++) ( Сопао1е.иггтеъгпе(1); вощ += ).; ) гетогп зощ; ): гесогп сГОЬ3; ) всаг1с чола Магп() ( // Получить результат подсчета.
Соопстс соипс = Соппсег()у гпг гево1Ю геви1С = сапог(3); Сопво1е.иггсеъьпе("Сумма 3 равна " + гево1Г) Сопво1е.игггеъгпе(); гево1г = соопг(5); Сопво1е.игьсеъьпе("Сумма 5 равна " + гевп1С) ) ) Ниже приведен результат выполнения этой программы. Обрати~с особое внимание на суммарное значение. 488 Часть ). Язык 0() о 1 2 з Сумма 3 равна б о 1 2 з в 5 Сумма 5 равна 21 Как видите, подсчет по-прежнему выполняется как обычно. Но обратите внимание на то, что сумма 5 теперь равна 21, а не 15( Дело в том, что переменная зша захватывается объектом ссо)>2 при его создании в методе соипсег () . Это означает, что она продолжает существовать вплоть до уничтожения делегата соспс при "сборке мусора" в самом конце программы. Следовательно, ее значение не уничтожается после возврата из метода Соппсег () или при каждом вызове анонимного метода, когда происходит обращение к делегату соппг в методе Нагп () .