Секреты LINQ. Автогенерируемые свойства. Инициализаторы объектов и коллекций, страница 15

В ней пропущено описание типа. Этим типом мог быть класс Customer, если бы такой класс был объявлен ранее. Но его нет. Так как extension-метод Select (или запрос) требует выбрать только два поля из пяти, указанных в инициализаторе объекта, то говорят, что объекты проецируются на кортеж (c.LastName, c.Addr).

Термин кортеж принят в нашей литературе по дискретной математике. В англоязычной литературе используют термин tuple, который имеет тот же смысл: упорядоченная последовательность полей. Иногда говорят n-tuple. В некоторых наших изданиях используют термин "n-ка" (энка — последовательность из n элементов).

При обработке запроса компилятор создает объекты типа <Anonymous Type>. Вы можете увидеть этот тип в окне отладчика Autos при пошаговом выполнении кода. Найдите в этом окне, какой тип компилятор вывел (infered) для самого запроса (объекта query). Описание этого типа выглядит так.

Enumerable.WhereSelectArrayIterator<<>f__AnonymousType1<string,string,string,string,string>,

<>f__AnonymousType2<string,string>> . . .

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

Предикаты

В пространстве имен System описан generic-делегат (то есть, делегатный тип) Predicate<>. Он определяет сигнатуру bool Predicate<T>(T). Переменная этого типа способна указывать на любую функцию, которая требует параметр произволного типа T и возвращает true или false. Покажем, как использовать предикат для вызова extension-метода FindAll. Последний работает с входной последовательностью и возвращает выходную последовательность, каждый элемент которой удовлетворяет условию, заданному предикатом.

Console.WriteLine("\nTest FindAll for Array");

Action<int> print = c => Console.Write(c + ", ");

int[] fib = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 }; // Ряд чисел Fibonacci

Predicate<int> pred = c => c % 2 == 1;

Array.ForEach<int> (Array.FindAll<int>(fib, pred), print);

¨  Работа ведется с массивом целых чисел.

¨  Generic-делегат print на лету создает функцию, которая выводит в консольное окно свой параметр.

¨  Generic-делегат pred создает функцию, возвращающую результат проверки своего аргумента на нечетность.

¨  Extension generic-метод FindAll пробегает по последовательности, заданной первым аргументом (fib), и применяет к каждому ее элементу метод, заданный делегатом print.

¨  Extension generic-метод ForEach пробегает по последовательности, заданной первым аргументом, и применяет к каждому ее элементу метод, заданный делегатом pred.

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

¨  Предикат pred, имеющий тип Predicate<int> (он же является делегатом), задан λ-выражением. Он позволяет отобрать нечетные числа из последовательности Fibonacci, возвращаемой extension-методом FindAll.

¨  Делегат print типа Action<int> также задан  задан λ-выражением, которое воздействует на каждый элемент последовательности, возвращаемой extension-методом ForEach.

Следующий пример производит те же действия, но с generic-списком типа List<int>. Обратите внимание на то, что синтаксис работы с типизированным списком проще.

Console.WriteLine("\nTest FindAll for List<int>");

List<int> list = new List<int>(fib);

list.FindAll(predicate).ForEach(print);

Категории стандартных операторов запроса

Класс Enumerable имеет множество статических методов для выполнения запросов к последовательностям (коллекцям, реализующим интерфейс IEnumerable<T>). В то же время класс Queryable имеет множество статических методов для выполнения запросов к структурам данных, реализующим интерфейс IQueryable <T>. Эти методы (операции) разбиты на 14 категорий (групп). Следующая таблица отображает эту классификацию.