主要好处在于这使得过滤操作(LINQ的核心)变得更加高效。(实际上,这是您提到的第一项优点)。
例如,考虑以下LINQ查询:
var results = collection.Select(item => item.Foo).Where(foo => foo < 3).ToList();
使用延迟执行,上述代码对集合进行了一次迭代,在迭代期间每次请求项目时,执行映射操作、筛选,然后使用结果构建列表。
如果让LINQ完全执行,则每个操作(Select / Where)都必须遍历整个序列。这将使链接操作非常低效。
个人而言,我认为你上面提到的第二点更像是一种副作用,而不是LINQ的好处——虽然有时候有益,但有些时候会导致混淆,所以我认为应该把它视为“需要理解的内容”,而不是夸大其作用,将其作为LINQ的优点。
针对你的编辑:
在你的特定示例中,在两种情况下,Select都会迭代集合并返回类型为item.Foo的IEnumerable I1。Where()然后枚举I1并返回item.Foo类型的IEnumerable<> I2。然后I2将被转换为List。
这不是正确的 - 延迟执行可以防止这种情况发生。
在我的示例中,返回类型为IEnumerable<T>,这意味着它是一个可以枚举的集合,但由于延迟执行,它实际上没有被枚举。
当你调用ToList()时,整个集合被枚举。结果在概念上看起来更像是(尽管当然不同):
List<Foo> results = new List<Foo>();
foreach(var item in collection)
{
var foo = item.Foo;
if (!(foo < 3))
continue;
results.Add(foo);
}
延迟执行会导致序列自身只被枚举(foreach)一次,在使用 ToList()
时进行。如果没有延迟执行,它的实现将更像是(概念上):
List<Foo> foos = new List<Foo>();
foreach(var item in collection)
{
foos.Add(item.Foo);
}
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);
}
IEnumerable<T>
,序列也不会每次枚举。 - Reed Copsey