Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 91
Текст из файла (страница 91)
А поскольку лямбда-выражение считается более эффективным, чем эквивалентный ему анонимный метод, то в большинстве случаев рекомендуется отдавать предпочтение именно ему. Лямбда-оператор Во всех лямбда-выражениях применяется новый лямбда-оператор =>, который разделяет лямбда-выражение на две части. В левой его части указывается входной параметр (или несколько параметров), а в правой части — тело лямбда-выражения. Оператор => иногда описывается такими словами, как "переходит" или "становится". В языке С() поддерживаются две разновидности лямбда-выражений в зависимости от тела самого лямбда-выражения. Так, если тело лямбда-выражения состоит из одного выражения, то образуется одиночное лямбда-выражение.
В этом случае тело выражения не заключается в фигурные скобки. Если же тело лямбда-выражения состоит из блока операторов, заключенных в фигурные скобки, то образуется блочное лямбда-вы)зажевие. При этом блочное лямбда-выражение может содержать целый ряд операторов, в том числе циклы, вызовы методов и условные операторы хг. Обе разновидности лямбда-выражений рассматриваются далее по отдельности. Одиночные лямбда-выражения В одиночном лямбда-выражении часть, находящаяся справа от оператора =>, воздействует на параметр (или ряд параметров), указываемый слева.
Возвращаемым результатом вычисления такого выражения является результат выполнения лямбда-оператора. Глава (5. Делегаты, события и лямбдв-вырвжеиия 473 Ниже приведена общая форма одиночного лямбда-выражения, принимающего единственный параметр. параметр => выражение Если же требуется указать несколько параметров, то используется следующая форма; (спнсок пяряметров) => яыряжение Таким образом, когда требуется указать два параметра или более, их следует заключить в скобки. Если же выражение не требует параметров, то следует использовать пустые скобки.
Ниже приведен простой пример одиночного лямбда-выражения. сопля => соипг т 2 В этом выражении поппе служит параметром, на который воздействует выражение соппс т 2. В итоге значение параметра сопле увеличивается на 2. А вот еще один пример одиночного лямбда-выражения: и => и % 2 == О В данном случае выражение возвращает логическое значение с где, если числовое значение параметра и оказывается четным, в противном случае — логическое значение 1а1яе.
Лямбда-выражение применяется в два этапа. Сначала объявляется тип делегата, совместимый с лямбда-выражением, а затем экземпляр делегата, которому присваивается лямбда-выражение. После этого лямбда-выражение вычисляется при обращении к экземпляру делегата. Результатом его вычисления становится возвращаемое значение. В приведенном ниже примере программы демонстрируется применение двух одиночных лямбда-выражений. Сначала в этой программе объявляются два типа делегатов. Первый из них, 1псг, принимает аргумент типа 1пс и возвращает результат того же типа Второй делегат, 1януеп, также принимает аргумент типа 1пг, но возвращает результат типа Ьоо1.
Затем экземплярам этих делегатов присваиваются одиночные лямбда-выражения. И наконец, лямбда-выражения вычисляются с помощью соответствующих экземпляров делегатов. // Применить два одиночных пямбдя-выражения, ия1пп Яуясев) // Объявить делегат, принимающий аргумент типа гпг и // возвращающий результат типа гпя. бе1епяге 1пг 1псг(гпг т)) // Объявить делегат, принимающий аргумент типа 1пя и // нозярящяющий результат типа Ьоо1.
бе1едяге Ьоо1 1яктеп(1пя т)т с1аяя Я1вр1еьявЬбяпево ( ята11с тогб Нагл() ( // Создать делегат тпсг, ссыляюяийся ня // лямбдя-выражение, увеличивающее свой // параметр ня 2. 1псг гпсг = солане => сонно + 2т 474 Часть !. Языг С» // й теперь использовать лямбда-выражение 1псг. Сопво1е.иггсевьпе("Использование лямбда-выражения гпсг: ") гпс х = -101 ни11е(х <= 0) ( Сопво1е.иг).се(х + " ")," х = гпсг(х)т // увеличить значение х на 2 ! Сопво1е.иг1се11пе ("М") т // Создать экземпляр делегата 1вЕчеп, ссылающийся // на лямбда-выражение, возвращающее логическое // значение Ггие, если его параметр имеет четное // значение, в противном случае — логическое значение Га1ве.
1вЕчеп гвБчеп = п => п $2 == От // й теперь использовать лямбда-выражение гвЕчеп. Сопво1е.нг1геъ1пе("Использование лямбда-выражения 1вЕчеп: ")т гог(1пг >=1) г <= 101 1++) 11(1вЕчеи(1)) Сопво1е.иг»сев»пе(г + " четное."); Вот к какому результату приводит выполнение этой программы: Использование лямбла-выражения 1псг: -10 -8 -б -4 -2 0 Использование лямбда-выражения 1ввчеп: 2 четное.
4 четное. б четное. 8 четное. 10 четнов. В данной программе особое внимание обратите на следующие строки объявлений: 1псг гпсг = сопит => соиле + 2) 1вЕчеп гвЕчеп = и => п % 2 == 0; В первой строке объявления экземпляру делегата 1псг присваивается одиночное лямбда-выражение, возвращающее результат увеличения на 2 значения параметра сопит. Это выражение может быть присвоено делегату 1псг, поскольку оно совместимо с объявлением данного делегата.
Аргумент, указываемый при обращении к экземпляру делегата 1п сг, передается параметру сопле, который и возвращает результат вычисления лямбдавыражения. Во второй строке объявления делегату 1знчеп присваивается выражение, возвращающее логическое значение Сгие, если передаваемый ему аргумент оказывается четным, а иначе — логическое значение Еа1зе. Следовательно, это лямбда-выражение совместимо с объявлением делегата 1вечеи. В связи со всем изложенным выше возникает резонный вопрос: каким образом компилятору становится известно о типе данных, используемых в лямбда-выражении, например, о типе 1пс параметра соопс в лямбда-выражении, присваиваемом экземпляру делегата гисг? Ответить на этот вопрос можно так; компилятор делает заключение о типе Глава 15. Делегаты, события и иямбдв-выражения 475 параметра и типе результата вычисления выражения по типу делегата.
Следовательно, параметры и возвращаемое значение лямбда-выражения должны быть совместимы по типу с параметрами и возвращаемым значением делегата. Несмотря на всю полезность логического заключения о типе данных, в некоторых случаях приходится явно указывать тип параметра лямбда-выражения. Для этого достаточно ввести конкретное название типа данных. В качестве примера ниже приведен другой способ объявления экземпляра делегата бпсг. 1псг 1псг = (ъпт соиле) => соиле Ь 2) Как видите, сопле теперь явно объявлен как параметр типа упт.
Обратите также внимание на использование скобок. Теперь они необходимы. (Скобки могут быть опущены только в том случае, если задается лишь один параметр, а его тип явно не указывается.) В предыдущем примере в обоих лямбда-выражениях использовался единственный параметр, но в целом у лямбда-выражений может быть любое количество параметров, в том числе и нулевое. Если в лямбда-выражении используется несколько параметров, их необхо(лоио заключить в скобки.
Ниже приведен пример применения лямбда-выражения с целью определить, находится ли значение в заданных пределах. (1ом, Ь1ЧЬ, ча1) => ча1 >= 1он ая ча1 <= ЬЬЧЬ) А вот как объявляется тип делегата, совместимого с этим лямбда-выражением; бе1ечате Ьоо1 1пвапче(ъпт 1онег, ъпг баррет, Ьпе и); Следовательно, экземпляр делегата 1ппапсе может быть создан следующим образом: 1пкапче гапдеок = (1он, ьтчь, ча1) => ча1 >= 1ом вя ча1 <= ьъдьг После этого одиночное лямбда-выражение может быть выполнено так, как показано ниже. 11 (гапчебх (1, 5, 3) ) Сопво1е, Ыгьпеьъпе ( "Число 3 находится в пределах от 1 до 5."); И последнее замечание: внешние переменные могут использоваться и захватываться в лямбда-выражениях таким же образом, как и в анонимных методах. Блочные лямбда-выражения Как упоминалось выше, существуют две разновидности лямбда-выражений.
Первая из них, одиночное лямбда-выражение, была рассмотрена в предыдущем разделе. Тело такого лямбда-выражения состоит только из одного выражения. Второй разновидностью является блочное лямбда-выражение. Для такого лямбда-выражения характерны расширенные возможности выполнения разнотипных операций, поскольку в его теле допускается указывать несколько операторов. Например, в блочном лямбда-выражении можно использовать циклы и условные операторы бй, объявлять переменные и т.д.
Создать блочное лямбда-выражение нетрудно. Для этого достаточно заключить тело выражения в фигурные скобки. Помимо возможности использовать несколько операторов, в остальном блочное лямбда-выражение практически ничем не отличается от только что рассмотренного одиночного лямбда-выражения. Ниже приведен пример применения блочного лямбда-выражения для вычисления и возврата факториала целого значения. // Продемонстрировать применение блочного лямбда-выражения. чвьпч Зувсеит 476 Часть (. Язык О» // Делегат Хпгор принимает один аргумент типа Дпг // и возвращает результат типа гпг. бе1едаге гпг 1пгор(1пг епб)) с1азз Ягагеюепгъаюпбапещо ( згаггс чогб Магп() ( // Блочное лямбда-выражение возвращает факториал // передаваемого ему значения. 1ПСОр гаСС = П к> ( 1пг г = 13 гог (гпг г=1; г <= и( 1ьь) с=1* гегцгп г) Сопво1е.иг1Сеъспе("Факториал 3 равен " т ГасС(3))) сопзо1е.иг1сеь1пе("Факториал 5 равен " + тасс(5))) ) ) При выполнении этого кода получается следующий результат: Факториал 3 равен 6 Факториал 5 равен 120 В приведенном выше примере обратите внимание иа то, что в теле блочного лямбдавыражения объявляется переменная г, организуется цика »ог и используется оператор гесцгп.
Все эти элементы вполне допустимы в блочном лямбда-выражеиии. И в этом отношении оио очень похоже иа анонимный метод. Следовательно, многие анонимные методы могут быть преобразованы в блочные лямбда-выражеиия при обновлении уиаследоваииого кода. (Как упоминалось выше, в версии С» 3.0 лямбда-выражеиия считаются более предпочтительным способом создания анонимных функций.) И еше одно замечание: когда в блочном лямбда-выражеиии встречается оператор гесцгп, ои просто обусловливает возврат из лямбда-выражеиия, ио ие возврат из охватывающего метода.