Основным преимуществом является то, что это позволяет фильтрующим операциям, ядру LINQ, быть намного более эффективным.(Это фактически ваш элемент № 1).
Например, возьмите запрос LINQ, подобный следующему:
var results = collection.Select(item => item.Foo).Where(foo => foo < 3).ToList();
При отложенном выполнении вышеприведенное повторяет вашу коллекцию один раз , и каждый раз, когда элемент запрашивается во время итерации, выполняет операцию сопоставления, фильтрует, а затем использует результаты для построения списка.
Если вы должны были полностью выполнить LINQ каждый раз, каждая операция (Select
/ Where
) придется перебирать всю последовательность.Это сделало бы цепные операции очень неэффективными.
Лично я бы сказал, что ваш пункт № 2 выше является скорее побочным эффектом, а не выгодой - хотя иногда он выгоден, он также вызывает некоторую путаницу враз, так что я бы просто рассмотрел это «что-то, чтобы понять», а не рекламировать это как преимущество LINQ.
В ответ на ваше редактирование:
В вашем конкретномНапример, в обоих случаях Select выполняет итерацию коллекции и возвращает IEnumerable I1 типа item.Foo.Затем Where () будет перечислять I1 и возвращать IEnumerable <> I2 типа item.Foo.Затем I2 будет преобразован в список.
Это не так - отложенное выполнение предотвращает это.
В моем примере тип возвращаемого значения IEnumerable<T>
, что означает, чтоэто коллекция, которую можно перечислить , но из-за отложенного выполнения она фактически не перечисляется.
Когда вы вызываете ToList()
, перечисляется вся коллекция.Результат в конечном итоге выглядит концептуально более похожим (хотя, конечно, иным):
List<Foo> results = new List<Foo>();
foreach(var item in collection)
{
// "Select" does a mapping
var foo = item.Foo;
// "Where" filters
if (!(foo < 3))
continue;
// "ToList" builds results
results.Add(foo);
}
Отложенное выполнение приводит к тому, что сама последовательность перечисляется только (foreach) один раз , когдаиспользуется (ToList()
).Без отложенного выполнения это выглядело бы больше (концептуально):
// Select
List<Foo> foos = new List<Foo>();
foreach(var item in collection)
{
foos.Add(item.Foo);
}
// Where
List<Foo> foosFiltered = new List<Foo>();
foreach(var foo in foos)
{
if (foo < 3)
foosFiltered.Add(foo);
}
List<Foo> results = new List<Foo>();
foreach(var item in foosFiltered)
{
results.Add(item);
}