Меню сайта |
|
|
Вход на сайт |
|
|
Поиск |
|
|
Статистика |
Онлайн всего: 1 Гостей: 1 Пользователей: 0 |
|
|
| | |
|
Многие стандартные операторы запросов имеют входной параметр, тип которого принадлежит семейству универсальных методов-делегатов Func<T, TResult>. Эти делегаты используют параметры типа для определения количества и типов входных параметров, а также тип возвращаемого значения делегата. Делегаты Func очень полезны для инкапсуляции пользовательских выражений, которые применяются к каждому элементу в наборе исходных данных. В качестве примера рассмотрим следующий тип делегата:
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
Можно создать экземпляр этого делегата как Func<int,bool> myFunc, где int — тип входного параметра, а bool — тип возвращаемого значения. Возвращаемое значение всегда указывается в последнем параметре типа. Func<int, string, bool>определяет делегат с двумя входными параметрами, типы которых — int и string, и типом возвращаемого значения bool.Следующий делегат Func при вызове возвращает значение true или false которое показывает равен ли входной параметр 5:
Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false of course
Также лямбда-выражения можно использовать, когда аргумент имеет тип Expression<Func>, например в стандартных операторах запроса, которые определены в System.Linq.Queryable. При задании аргумента типа Expression<Func> лямбда-выражение компилируется в дерево выражения.
Пример использования стандартного оператора запроса, метода Count, показан ниже:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
Компилятор может вывести тип входного параметра; а также его можно определить явно. Данное конкретное лямбда-выражение подсчитывает количество целых чисел (n), которые при делении на два дают остаток 1.
Следующая строка кода создает последовательность, которая содержит все элементы массива numbers, расположенные слева от 6, поскольку это первое число последовательности, не удовлетворяющее условию:
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
В этом примере показано, как задать несколько входных параметров путём заключения их в скобки. Этот метод возвращает все элементы в массиве чисел до того числа, величина которого меньше номера его позиции. Не следует путать лямбда-оператор (=>) с оператором "больше или равно" (>=).
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
При написании лямбда-выражений обычно не требуется указывать тип входных параметров, поскольку компилятор может выводить этот тип на основе тела лямбда-выражения, типа делегата параметра и других факторов, как описано в спецификации языка C#. Для большинства стандартных операторов запроса первый входной параметр имеет тот же тип, что и элементы в исходной последовательности. Поэтому, если производится запрос к IEnumerable<Customer>, то переменная входного параметра расценивается как объект типа Customer, а это означает, что у вас есть доступ к его методам и свойствам.
customers.Where(c => c.City == "London");
Используются следующие основные правила для лямбда-выражений:
-
лямбда-выражение должно содержать то же число параметров, что и тип делегата;
-
Каждый входной параметр в лямбда-выражении должен быть неявно преобразуемым в соответствующий параметр делегата.
-
возвращаемое значение лямбда-выражения (если таковое имеется) должно быть неявно преобразуемым в возвращаемый тип делегата.
Обратите внимание: лямбда-выражения сами по себе не имеют типа, поскольку система общих типов не имеет встроеной концепции "лямбда-выражения". Однако иногда бывает удобно оперировать неформальным понятием "типа" лямбда-выражения. При этом под типом понимается тип делегата или тип Expression, в который преобразуется лямбда-выражение.
Лямбда-выражения могут ссылаться на внешние переменные (см. Анонимные методы (Руководство по программированию в C#)), находящиеся в области метода, в котором определена лямбда-функция, или в области типа, который содержит лямбда-выражение. Переменные, полученные таким способом, сохраняются для использования в лямбда-выражениях, даже если бы в ином случае они оказались за границами области действия и уничтожились сборщиком мусора. Внешней переменной должно быть присвоено определённое значение, прежде чем она сможет использоваться в лямбда-выражениях. Следующий пример демонстрирует применение этих правил:
delegate bool D();
delegate bool D2(int i);
class Test
{
D del;
D2 del2;
public void TestMethod(int input)
{
int j = 0;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () => { j = 10; return j > input; };
// del2 will be invoked after TestMethod goes out of scope.
del2 = (x) => {return x == j; };
// Demonstrate value of j:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j); // Invoke the delegate.
bool boolResult = del();
// Output: j = 10 b = True
Console.WriteLine("j = {0}. b = {1}", j, boolResult);
}
static void Main()
{
Test test = new Test();
test.TestMethod(5);
// Prove that del2 still has a copy of
// local variable j from TestMethod.
bool result = test.del2(10);
// Output: True
Console.WriteLine(result);
Console.ReadKey();
}
}
Следующие правила применимы к области действия переменной в лямбда-выражениях.
-
Захваченная переменная не будет уничтожена сборщиком мусора до тех пор, пока делегат, который на нее ссылается, не перейдет в статус подлежащего уничтожению при сборке мусора.
-
Переменная, объявленная в лямбда-выражении, невидима во внешнем методе.
-
Лямбда-выражение не может непосредственно захватывать параметры ref или out из метода, в котором они находятся.
-
Оператор Return в лямбда-выражении не приводит к возврату (завершению) метода, в котором объявлено/вызвано лямбда-выражение.
-
Лямбда-выражение не может содержать оператора goto, оператора break или оператора continue внутри лямбда-функции, если целевой объект перехода находится вне блока. Если целевой объект находится внутри блока, то наличие оператора перехода за пределами лямбда-функции также будет ошибкой.
Дополнительные сведения см. в Спецификация языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
Ссылки
Основные понятия
Другие ресурсы
| |
| | |
|