Шрифт:
Интервал:
Закладка:
System.Collections.IEnumerable subset =
from i in numbers
where i < 10
select i;
К счастью, неявная типизация при работе с запросами LINQ значительно проясняет картину:
static void QueryOverInts()
{
int[] numbers = {10, 20, 30, 40, 1, 2, 3, 8};
<b> // Здесь используется неявная типизация...</b>
var subset = from i in numbers where i < 10 select i;
<b> // ...и здесь тоже.</b>
foreach (var i in subset)
{
Console.WriteLine("Item: {0} ", i);
}
ReflectOverQueryResults(subset);
}
В качестве эмпирического правила: при захвате результатов запроса LINQ всегда необходимо использовать неявную типизацию. Однако помните, что (в большинстве случаев) действительное возвращаемое значение имеет тип, реализующий интерфейс IEnumerable<T>.
Какой точно тип кроется за ним (OrderedEnumerable<TElement, ТКеу>, WhereArrayIterator<T> и т.п.), к делу не относится, и определять его вовсе не обязательно. Как было показано в предыдущем примере кода, для прохода по извлеченным данным можно просто применить ключевое слово var внутри конструкции foreach.
LINQ и расширяющие методы
Несмотря на то что в текущем примере совершенно не требуется напрямую писать какие-то расширяющие методы, на самом деле они благополучно используются на заднем плане. Выражения запросов LINQ могут применяться для прохода по содержимому контейнеров данных, которые реализуют обобщенный интерфейс IEnumerable<T>. Тем не менее, класс System.Array (используемый для представления массива строк и массива целых чисел) не реализует этот контракт:
// Похоже, что тип System.Array не реализует
// корректную инфраструктуру для выражений запросов!
public abstract class Array : ICloneable, IList,
IStructuralComparable, IStructuralEquatable
{
...
}
Хотя класс System.Array не реализует напрямую интерфейс IEnumerable<T>, он косвенно получает необходимую функциональность данного типа (а также многие другие члены, связанные с LINQ) через статический тип класса System.Linq.Enumerable.
В служебном классе System.Linq.Enumerable определено множество обобщенных расширяющих методов (таких как Aggregate<T>(), First<T>(), Мах<Т>() и т.д.), которые класс System.Array (и другие типы) получают в свое распоряжение на заднем плане. Таким образом, если вы примените операцию точки к локальной переменной currentVideoGames, то обнаружите большое количество членов, которые отсутствуют в формальном определении System.Array.
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})Роль отложенного выполнения
Еще один важный момент, касающийся выражений запросов LINQ, заключается в том, что фактически они не оцениваются до тех пор, пока не начнется итерация по результирующей последовательности. Формально это называется отложенным выполнением. Преимущество такого подхода связано с возможностью применения одного и того же запроса LINQ многократно к тому же самому контейнеру и полной гарантией получения актуальных результатов. Взгляните на следующее обновление метода QueryOverlnts():
static void QueryOverInts()
{
int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 };
// Получить числа меньше 10.
var subset = from i in numbers where i < 10 select i;
<b> // Оператор LINQ здесь оценивается!</b>
foreach (var i in subset)
{
Console.WriteLine("{0} < 10", i);
}
Console.WriteLine();
// Изменить некоторые данные в массиве.
numbers[0] = 4;
<b> // Снова производится оценка!</b>
foreach (var j in subset)
{
Console.WriteLine("{0} < 10", j);
}
Console.WriteLine();
ReflectOverQueryResults(subset);
}
На заметку! Когда оператор LINQ выбирает одиночный элемент (с использованием First()/FirstOrDefault(), Single()/SingleOrDefault() или любого метода агрегирования), запрос выполняется немедленно. Методы First(), FirstOrDefault(), Single() и SingleOrDefault будут описаны в следующем разделе. Методы агрегирования раскрываются позже в главе.
Ниже показан вывод, полученный в результате запуска программы. Обратите внимание, что во второй итерации по запрошенной последовательности появился дополнительный член, т.к. для первого элемента массива было установлено значение меньше 10:
- Понимание SQL - Мартин Грубер - Базы данных