Добавить в цитаты Настройки чтения

Страница 228 из 502

Несмотря на то что применение захваченных переменных может привести к довольно неожиданным результатам, как в приведенном выше примере, оно все же логически обоснованно. Ведь когда анонимный метод захватывает переменную, она продолжает существовать до тех пор, пока используется захватывающий ее делегат. В противном случае захваченная переменная оказалась бы неопределенной, когда она могла бы потребоваться делегату.

Лямбда-выражения

Несмотря на всю ценность анонимных методов, им на смену пришел более совершенный подход: лямбда-выражение. Не будет преувеличением сказать, что лямбда-выражение относится к одним из самых важных нововведений в С#, начиная с выпуска исходной версии 1.0 этого языка программирования. Лямбда-выражение основывается на совершенно новом синтаксическом элементе и служит более эффективной альтернативой анонимному методу. И хотя лямбда-выражения находят применение главным образом в работе с LINQ (подробнее об этом — в главе 19), они часто используются и вместе с делегатами и событиями. Именно об этом применении лямбда-выражений и пойдет речь в данном разделе.

Лямбда-выражение — это другой собой создания анонимной функции. (Первый ее способ, анонимный метод, был рассмотрен в предыдущем разделе.) Следовательно, лямбда-выражение может быть присвоено делегату. А поскольку лямбда-выражение считается более эффективным, чем эквивалентный ему анонимный метод, то в большинстве случаев рекомендуется отдавать предпочтение именно ему.

Во всех лямбда-выражениях применяется новый лямбда-оператор =>, который разделяет лямбда-выражение на две части. В левой его части указывается входной параметр (или несколько параметров), а в правой части — тело лямбда-выражения. Оператор => иногда описывается такими словами, как "переходит" или "становится".

В C# поддерживаются две разновидности лямбда-выражений в зависимости от тела самого лямбда-выражения. Так, если тело лямбда-выражения состоит из одного выражения, то образуется одиночное лямбда-выражение. В этом случае тело выражения не заключается в фигурные скобки. Если же тело лямбда-выражения состоит из блока операторов, заключенных в фигурные скобки, то образуется блочное лямбда-выражение. При этом блочное лямбда-выражение может содержать целый ряд операторов, в том числе циклы, вызовы методов и условные операторы if. Обе разновидности лямбда-выражений рассматриваются далее по отдельности.

В одиночном лямбда-выражении часть, находящаяся справа от оператора =>, воздействует на параметр (или ряд параметров), указываемый слева. Возвращаемым результатом вычисления такого выражения является результат выполнения лямбда-оператора.

Ниже приведена общая форма одиночного лямбда-выражения, принимающего единственный параметр.

<b>параметр =&gt; выражение</b>

Если же требуется указать несколько параметров, то используется следующая форма.

<b>(список_параметров) =&gt; выражение</b>

Таким образом, когда требуется указать два параметра или более, их следует заключить в скобки. Если же выражение не требует параметров, то следует использовать пустые скобки.

Ниже приведен простой пример одиночного лямбда-выражения.

<b>count =&gt; count + 2</b>

В этом выражении count служит параметром, на который воздействует выражение count + 2. В итоге значение параметра count увеличивается на 2. А вот еще один пример одиночного лямбда-выражения.

<b>n =&gt; n % 2 == 0</b>

В данном случае выражение возвращает логическое значение true, если числовое значение параметра n оказывается четным, а иначе — логическое значение false.

Лямбда-выражение применяется в два этапа. Сначала объявляется тип делегата, совместимый с лямбда-выражением, а затем экземпляр делегата, которому присваивается лямбда-выражение. После этого лямбда-выражение вычисляется при обращении к экземпляру делегата. Результатом его вычисления становится возвращаемое значение.

В приведенном ниже примере программы демонстрируется применение двух одиночных лямбда-выражений. Сначала в этой программе объявляются два типа делегатов. Первый из них, Incr, принимает аргумент типа int и возвращает результат того же типа. Второй делегат, IsEven, также принимает аргумент типа int, но возвращает результат типа bool. Затем экземплярам этих делегатов присваиваются одиночные лямбда-выражения. И наконец, лямбда-выражения вычисляются с помощью соответствующих экземпляров делегатов.

<b>// Применить два одиночных лямбда-выражения.</b>

<b>using System;</b>

<b>// Объявить делегат, принимающий аргумент типа int и </b>

<b>// возвращающий результат типа int.</b>

<b>delegate int Incr(int v);</b>

<b>// Объявить делегат, принимающий аргумент типа int и </b>

<b>// возвращающий результат типа bool,</b>

<b>delegate bool IsEven(int v);</b>

<b>class SimpleLambdaDemo {</b>

<b>  static void Main() {</b>

<b>    // Создать делегат Incr, ссылающийся на лямбда-выражение,</b>

<b>    // увеличивающее свой параметр на 2.</b>

<b>    Incr incr = count =&gt; count + 2;</b>

<b>    // А теперь использовать лямбда-выражение incr.</b>

<b>    Console.WriteLine(&quot;Использование лямбда-выражения incr: &quot;);</b>

<b>    int x = -10;</b>

<b>    while(x &lt;= 0) {</b>

<b>      Console.Write(x + &quot; &quot;);</b>

<b>      x = incr(x); // увеличить значение x на 2</b>