Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю
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>
foreach
LINQ и расширяющие методы
Несмотря на то что в текущем примере совершенно не требуется напрямую писать какие-то расширяющие методы, на самом деле они благополучно используются на заднем плане. Выражения запросов LINQ могут применяться для прохода по содержимому контейнеров данных, которые реализуют обобщенный интерфейс
IEnumerable<T>
System.Array
// Похоже, что тип System.Array не реализует
// корректную инфраструктуру для выражений запросов!
public abstract class Array : ICloneable, IList,
IStructuralComparable, IStructuralEquatable
{
...
}
Хотя класс
System.Array
IEnumerable<T>
System.Linq.Enumerable
В служебном классе
System.Linq.Enumerable
Aggregate<T>()
First<T>()
Мах<Т>()
System.Array
currentVideoGames
System.Array
Роль отложенного выполнения
Еще один важный момент, касающийся выражений запросов 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: