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