Захват переменных анонимными методами. Цепочка вызовов.

При объявлении анонимных методов любые переменные, объявленные вне контекста анонимного метода, но доступные внутри него, включая ссылку this, рассматриваются как внешние переменные. И если тело анонимного метода ссы­лается на эти переменные, то говорят, что анонимный метод "захватил" перемен­ную.

Public static void Search(list <string> list, string substr)

{

return list.Find(delegate(string x) {return x.Starts with (substr);});

}

Здесь в метод Search передается параметр substr. Этот параметр используется в анонимном методе (вместо него может использовать другая любая локальная переменная, но интересны те локальные переменные, которые хранятся в стеке). Далее из анонимного метода создается делегат, но он может быть передан в другие точки программы, т.е. возможна ситуация, когда делегат вызывается после того, как локальная переменная вышла из зоны видимости.

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

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

19. Лямбда-выражения и лямбда-операторы. Синтаксис, назначение и простейшие формы.

Используя λ-выражения, можно кратко определять функциональные объекты для использования в любое время. C# всегда поддерживал эту возможность через делегаты, посредством которых создается функциональный объект (в форме делегата) и к нему привязывается код обратного вызова во время создания. λ-выражения связывают эти два действия – создание и подключение – в один выразительный оператор кода. Вдобавок можно легко ассоциировать среду с функциональными объектами.

λ-выражение – это синтаксис, посредством которого можно объявлять анонимные функции (делегаты) более гладким и выразительным способом.

λ-выражение – особая форма функционального программирования для императивного языка.

λ-выражение позволяет в краткой форме определять функциональные объекты.

В основе λ-выражений лежат делегаты. В обычной форме нужно создать делегат и подключить его к методу для обратного вызова. λ-выражение позволяет соединить два этапа в один. У λ-выражений имеется две формы:

1) пишется некий код, который завершается оператором return. Форма, которая наиболее прямо заменяет анонимные методы, представляет собой блок кода, заключенный в фигурные скобки. Это λ-операторы. Такие λ-операторы – прямая замена анонимных методов.

2) λ-выражения предоставляют еще более сокращенный способ объявлять анонимный метод и не требуют ни кода в фигурных скобках, ни оператора return.

Оба типа λ-выражений могут быть преобразованы в делегаты. Однако λ-выражения без блоков операторов можно преобразовать в деревья выражений с помощью типов из пространства имен System.Linq.Expressions. Другими словами, функция, описанная в коде, превращается в данные.

Синтаксис:

<(список операторов)> => λ-выражение

Например, следующее λ-выражение может быть использовано в качестве делегата, принимающего один параметр и возвращающего результат выполнения операции над параметром: х => х/2, где х - атрибут, а х/2 - λ-выражение. Это говорит следующее: “взять x в качестве параметра и вернуть результат следующей операции в x”.

λ-выражение лишено информации о типе. Это не значит, что выражение не имеет типа. Вместо этого компилятор выводит тип аргумента и тип результата из контекста его использования, и отсюда следует, что если вы присваиваете λ-выражение делегату, типы определения делегата используются для определения типов внутри λ-выражения.

Func<int, double> expr = x => x/2;

Console.WriteLine (expr(5));

Тип Func<> – это новый вспомогательный тип, представленный в пространстве имен System, который используется для объявления простых делегатов, принимающих до четырех аргументов и возвращающих результат.

В данном случае объявляется переменная expr, которая является делегатом, принимающим int и возвращающим double.

Public delegate TResult Func <TSouree; TResult>(TSouree souree);

Func<int, int, int> exp r = (x, y) => x+y;

λ-выражения как и делегаты в состоянии захватывать внешние переменные.

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

public static int GetCount<TItem>(IList <TItem>souree, Predicate<TItem> predicate)

{

int count = 0;

foreach(var x in souree)

if(predicate(x)) count ++;

return count;

}

List <string> list = new List<string>() {};

int c = GetCount(list, x => x.Substr(“Петуш”) >= 0);

Или

List <string> list = new List<int>() {2, 3, 4, 7}

int c = GetCount(list, x => x %2 == 0);

Кроме λ-выражений есть λ-операторы. Отличие состоит в том, что λ-операторы имеют внутри себя оператор return аналогично анонимным методам.

Func <int, int, int> expr = (x, y) =>{return x+y;}

И есть одно главное отличие между λ-выражениями с блоками операторов и простыми λ-выражениями. Первые могут быть преобразованы только в типы делегатов, в то время как вторые – и в делегаты, и в деревья выражений, посредством семейства типов, сосредоточенных вокруг System.Linq.Expressions.Expression<T>.


Наши рекомендации