主要好处是,这使得 LINQ 的核心过滤操作变得更加高效。 (这实际上是你的第一个项目)。
例如,采用如下所示的 LINQ 查询:
var results = collection.Select(item => item.Foo).Where(foo => foo < 3).ToList();
通过延迟执行,上面的代码会迭代您的集合one time,并且每次在迭代期间请求一个项目时,都会执行映射操作、过滤,然后使用结果来构建列表。
如果你要让 LINQ 每次都完全执行,每个操作 (Select
/ Where
) 必须迭代整个序列。这将使链式操作效率非常低。
就我个人而言,我想说你上面的第2项更多的是副作用而不是好处——虽然它有时是有益的,但有时也会引起一些混乱,所以我只会考虑这是“需要理解的东西”并且不要将其宣传为 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)
{
// "Select" does a mapping
var foo = item.Foo;
// "Where" filters
if (!(foo < 3))
continue;
// "ToList" builds results
results.Add(foo);
}
延迟执行导致序列本身仅被枚举(foreach)one time,当它被使用时(通过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);
}