Язык программирования C#9 и платформа .NET5
Шрифт:
Console.WriteLine("******** Discards with Anonymous Methods ********");
Func<int,int,int> constant = delegate (int _, int _) {return 42;};
Console.WriteLine("constant(3,4)={0}",constant(3,4));
Понятие лямбда-выражений
Чтобы завершить знакомство с архитектурой событий .NET Core, необходимо исследовать лямбда-выражения. Как объяснялось ранее в главе, язык C# поддерживает возможность обработки событий "встраиваемым образом", позволяя назначать блок операторов
В целях подготовки фундамента для изучения лямбда-выражений создайте новый проект консольного приложения по имени
LambdaExpressions
. Для начала взгляните на метод FindAll
обобщенного класса List<T>
. Данный метод можно вызывать, когда нужно извлечь подмножество элементов из коллекции; вот его прототип:
// Метод класса System.Collections.Generic.List<T>.
public List<T> FindAll(Predicate<T> match)
Как видите, метод
FindAll
возвращает новый объект List<T>
, который представляет подмножество данных. Также обратите внимание, что единственным параметром FindAll
является обобщенный делегат типа System.Predicate<T>
, способный указывать на любой метод, который возвращает bool
и принимает единственный параметр:
// Этот делегат используется методом FindAll
// для извлечения подмножества.
public delegate bool Predicate<T>(T obj);
Когда вызывается
FindAll
, каждый элемент в List<T>
передается методу, указанному объектом Predicate<T>
. Реализация упомянутого метода будет выполнять некоторые вычисления для проверки соответствия элемента данных заданному критерию, возвращая в результате true
или false
. Если метод возвращает true
, то текущий элемент будет добавлен в новый объект List<T>
, который представляет интересующее подмножество. Прежде чем мы посмотрим, как лямбда-выражения могут упростить работу с методом
FindAll
, давайте решим задачу длинным способом, используя объекты делегатов непосредственно. Добавьте в класс Program
метод (TraditionalDelegateSyntax
), который взаимодействует с типом System.Predicate<T>
для обнаружения четных чисел в списке List<T>
целочисленных значений:
using System;
using System.Collections.Generic;
using LambdaExpressions;
Console.WriteLine("***** Fun with Lambdas *****\n");
TraditionalDelegateSyntax;
Console.ReadLine;
static void TraditionalDelegateSyntax
{
// Создать список целочисленных значений.
List<int> list = new List<int>;
list.AddRange(new int[] { 20, 1, 4, 8, 9, 44 });
//
Вызвать FindAll с применением традиционного синтаксиса делегатов.
Predicate<int> callback = IsEvenNumber;
List<int> evenNumbers = list.FindAll(callback);
Console.WriteLine("Here are your even numbers:");
foreach (int evenNumber in evenNumbers)
{
Console.Write("{0}\t", evenNumber);
}
Console.WriteLine;
}
// Цель для делегата Predicate<>.
static bool IsEvenNumber(int i)
{
// Это четное число?
return (i % 2) == 0;
}
Здесь имеется метод (
IsEvenNumber
), который отвечает за проверку входного целочисленного параметра на предмет четности или нечетности с применением операции получения остатка от деления (%
) языка С#. Запуск приложения приводит к выводу на консоль чисел 20, 4, 8 и 44. Наряду с тем, что такой традиционный подход к работе с делегатами ведет себя ожидаемым образом,
IsEvenNumber
вызывается только при ограниченных обстоятельствах — в частности, когда вызывается метод FindAll
, который возлагает на нас обязанность по полному определению метода. Если взамен использовать анонимный метод, то можно превратить это в локальную функцию и код станет значительно чище. Добавьте в класс Program
следующий новый метод:
static void AnonymousMethodSyntax
{
// Создать список целочисленных значений.
List<int> list = new List<int>;
list.AddRange(new int[] { 20, 1, 4, 8, 9, 44 });
// Теперь использовать анонимный метод.
List<int> evenNumbers =
list.FindAll(delegate(int i) { return (i % 2) == 0; } );
// Вывести четные числа
Console.WriteLine("Here are your even numbers:");
foreach (int evenNumber in evenNumbers)
{
Console.Write("{0}\t", evenNumber);
}
Console.WriteLine;
}
В данном случае вместо прямого создания объекта делегата
Predicate<T>
и последующего написания отдельного метода есть возможность определить метод как анонимный. Несмотря на шаг в правильном направлении, вам по-прежнему придется применять ключевое слово delegate
(или строго типизированный класс Predicate<T>
) и обеспечивать точное соответствие списка параметров:
Поделиться с друзьями: