Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 90
Текст из файла (страница 90)
Анонимные функции Метод, на который ссылается делегат, нередко используется только для этой цели. Иными словами, единственным основанием для существования метода служит то обстоятельство, что он может быть вызван посредством делегата, но сам он не вызывается вообще. В подобных случаях можно воспользоваться анонимной фуню(иай, чтобы не создавать отдельный метод. Анонимная функция, по существу, представляет собой безымянный кодовый блок, передаваемый конструктору делегата. Преимущество анонимной функции состоит, в частности, в ее простоте.
Благодаря ей отпадает необходимость объявлять отдельный метод, единственное назначение которого состоит в том, что он передается делегату Начиная с версии 3.0 в С(т предусмотрены две разновидности анонимных функций: анонимные методы и лямбда-выражении. Анонимные методы были внедрены в С(т еще в версии 2.0, а лямбда-выражения — в версии 3.0. В целом лямбда-выражение совершенствует принцип действия анонимного метода и в настоящее время считается более предпочтительным для создания анонимной функции. Но анонимные методы широко применяются в существующем коде С(т и поэтому по-прежнему являются важной составной частью С(т.
А поскольку анонимные методы предшествовали появлению лямбдавыражений, то ясное представление о них позволяет лучше понять особенности лямбдавыражений. К тому же анонимные методы могут быль использованы в целом ряде случаев, где применение лямбда-выражений оказывается невозможным. Именно поэтому в этой главе рассматриваются и анонимные методы, и лямбда-выражения. Анонимные методы Анонимный метод — один из способов создания безымянного блока кода, связанного с конкретным экземпляром делегата. Для создания анонимного метода достаточно указать кодовый блок после ключевого слова с(е1едасе. Покажем, как это делается, на конкретном примере. В приведенной ниже программе анонимный метод служит для подсчета от 0 до 5.
// Продемонстрировать применение анонимного метода. паллу Зуалеит /! Объявить тип делегата. бе1епаге тола Соппг1С((т о1ааа ЛпопМел(тбеио ( влагьо тоьб Маьп() ( 468 Часть!. Язык Сз // далее следует код дпя подсчета чисел, // передаваемый делегату в качестве // анонимного метода. соипс1с сонпс = бе1ечасе ( // Этот кодовый блок передается делегату. кос(1ПС 1=02 1 <= 52 1+т) Сопзо1е.нг1Сесспе(1)т ); // обратите внимание на точку с запятой соипс() т ) ) В данной программе сначала объявляется тип делегата СоппС1С без параметров и с возвращаемым типом новб. Далее в методе мауп () создается экземпляр соппс делегата СоопС1С, которому передается кодовый блок, следующий после ключевого слова бе1едапе.
Именно этот кодовый блок и является анонимным методом, который будет выполняться при обращении к делегату соопс. Обратите внимание на то, что после кодового блока следует точка с запятой, фактически завершающая оператор объявления. Ниже приведен результат выполнения данной программы. Передача аргументов анонимному методу Анонимному методу можно передать один аргумент или более.
Для этого достаточно указать в скобках список параметров после ключевого слова бе1едаСе, а при обращении к экземпляру делегата — передать ему соответствующие аргументы. В качестве примера ниже приведен вариант предыдущей программы, переделанный с целью передать в качестве аргумента конечное значение для подсчета. // Продемонстрировать применение анониыного метода, // принимающего аргумент. чзвпд Зувсепы // Обратите внимание на то, что теперь у делегата // СоипС1С имеется параметр.
бе1есаке ноги СонпС1С(тпС епб); с1азв апопМеьппещо2 ( вгвкас нояб Маьп() ( // Здесь конечное значение дпя подсчета передается // анонимному методу. СочпС1С соипС = бе1едаке (впС епб) ( Гог(апс 1=0; 1 <= епбт ст+] Глава (б. Делегаты, события я ляыбда-еыражеяяя 469 Сопвс1е.ыг1геьяпе (1) ) сонно(3)я Сспвс1е.ыгтпеьтпе()я сорос(5)я В этом варианте программы делегат Ссопт1С принимает целочисленный аргумент.
Обратите внимание иа то, что при создании анонимного метода список параметров указывается после ключевого слова ((е1еоаге. Параметр епс( становится доступным для кода в анонимном методе таким же образом, как и при создании именованного метода. Ниже приведеи результат выполнения данной программы. Возврат значения из анонимного метода Анонимный метод может возвращать значение.
Для этой цели служит оператор геспгп, действующий в анонимном методе таким же образом, как и в именованном методе. Как и следовало ожидать, тип возвращаемого значения должен быть совместим с возвращаемым типом, указываемым в объявлении делегата. В качестве примера ниже приведеи код, выполняющий подсчет с суммированием и возвращающий результат. // Продемонстрировать применение анонимного метода, // возвращающего значение. пв1пд Зувпещя // этот делегат возвращает значение. ое1едапе япп Соппптя(тпп епо)) с1авв апспМеялвещсз ( впасяс толы Ма1п() япя гевп1Ю // Здесь конечное значение дпя подсчета передается // анонимному методу.
а возвращается сумма // подсчитанных чисел. Ссипгтг свинг = Ое1еоаге (лпг епс) ( япс внщ = О," 470 Часть ). язык Сз гог(1пг г=с; г <= епси 1+ь) [ Сопзо1е.нг1сеъ1пе(1)! зоз += 1; ) гегогп зии; !! возвратить значение из анонимного метода гезп1г = ооппг(3); Сопзо1е.нг1сеь1пе("Сумма 3 равна " э гезо1С); Сопзо1е.нгъгеъ1пе(); гези1С = соппг(5); Сопзо1е.нг1те11пе("Сумма 5 равна " + гезо1С); ) ) В этом варианте кода суммарное значение возвращается кодовым блоком, связанным с экземпляром делегата соппс.
Обратите внимание на то, что оператор геспгп применяется в анонимном методе таким же образом, как и в именованном методе. Ниже приведен результат выполнения данного кода. О 1 г 3 Сумма 3 равна 5 О 1 2 3 л 5 Сумма 5 равна 15 Применение внешних переменных в анонимных методах Локальная переменная, в область действия которой входит анонимный метод, называется внешней переменной. Такие переменные доступны для использования в анонимном методе.
И в этом случае внешняя переменная считается захваченной. Захваченная переменная существует до тех пор, пока захвативший ее делегат ие будет собран в "мусор". Поэтому если локальная переменная, которая обычно прекращает свое существование после выхода из кодового блока, используется в анонимном методе, то оиа продолжает сушествовать до тех пор, пока ие будет уничтожен делегат, ссылаюшийся иа этот метод. Захват локальной переменной может привести к неожиданным результатам.
В качестве примера рассмотрим еше один вариант программы подсчета с суммированием чисел. В данном варианте объект соппстс конструируется и возвращается статическим методом соппсег () . Этот объект использует переменную зпль объявленную в охватывающей области действия метода соппсег (), а не самого анонимного метода Поэтому переменная эпи захватывается анонимным методом.
Метод Соппгег () вызывается в методе Иагп () для получения объекта СоппС1С, а следовательно, переменная зпв ие уничтожается до самого конца программы. Глава! б. Делегаты, события и ляыбда-еыражения 471 // Продемонстрировать применение захваченной переменной. оя1пд Буясепц // Этот делегат возвращает значение типа 1пс и принимает аргумент типа 1пс. г(е1едаее 1пг соппе1С(1пп епп)т с1аяв Уагсарппге ( ясаегс Соппс1С Соппоег() 1пл япщ = От // Здесь подсчитанная сумма сохраняется в переменной яощ.
Соопе1С сСОЬ3 = г(е1едате (1пг епг() ( лог(1пп г=о( г < епоп 1ЬЬ) ( Сопяо1е.нг1ееьгпе(1) т яищ += 1т ) гегпгп яшпт )т гепцгп сСОЬ3т япаС1с чо(Н Иагп() ( // Получить результат подсчета. Соппг1С соопс = Сопппег()т 1пт геяо1от геяи1С = сопит(3)т Сопяо1е.нггееХгпе("Сумма 3 равна " + геяо1С); Сопяо1е.ИглпеХгпе() т геяо1С = сонно(5)т Сопво1е.Иггпепапе("Сумма 5 равна " + геяп1С)т ) ) Ниже приведен результат выполнения этой программы.
Обратите особое внимание на суммарное значение. О 1 2 3 Сумма 3 равна б О 1 2 3 4 5 Сумма 5 равна 21 472 Часть (. Язык С() Как видите, подсчет по-прежнему производится как обычно. Но обратите внимание на то, что сумма 5 теперь равна 21, а не 151 Дело в том, что переменная зокз захватывается объектом ссо)>б при его создании в методе соппсег () . Это означает, что она продолжает существовать вплоть до уничтожения делегата соппс при "сборке мусора" в самом конце программы. Следовательно, ее значение не уничтожается после возврата из метода соппсег () или при каждом вызове анонимного метода, когда происходит обращение к делегату соипс в методе маъп () . Несмотря на то что применение захваченных переменных может привести к довольно неожиданным результатам, как в приведенном выше примере, оно все же логически обоснованно. Ведь когда анонимный метод захватывает переменную, она продолжает существовать до тех пор, пока используется захватывающий ее делегат.
В противном случае захваченная переменная оказалась бы неопределенной, когда она могла бы потребоваться делегату Лямбда-выражения Несмотря на всю ценность анонимных методов, им на смену пришел более совершенный подход: лямбда-вькражеяие. Не будет преувеличением сказать, что лямбдавыражение относится к одному из двух самых важных нововведений в версии С(г 3.0 (другим считается Е1ХО).
Лямбда-выражение основывается на совершенно новом синтаксическом элементе и служит более эффективной альтернативой анонимному методу. И хотя лямбда-выражения находят применение главным образом в работе с ЕПЩ (подробнее об этом — в главе 19), они часто используются и вместе с делегатами и событиями. Именно об этом применении лямбда-выражений и пойдет речь в данном разделе. Лямбда-выражение — это другой собой создания анонимной функции. (Первый ее способ, анонимный метод, был рассмотрен в предыдущем разделе.) Следовательно, лямбда-выражение может быть присвоено делегату.