LINQ 中的延迟执行有什么好处?

2024-05-26

LINQ 使用延迟执行模型,这意味着在调用 Linq 运算符时不会返回结果序列,而是这些运算符返回一个对象,然后仅当我们枚举该对象时,该对象才会生成序列的元素。

虽然我了解延迟查询的工作原理,但我在理解延迟执行的好处时遇到了一些困难:

1)我读到,仅当您真正需要结果时才执行延迟查询会带来很大的好处。那么这个好处是什么呢?

2)延迟查询的另一个优点是,如果您定义一次查询,那么每次枚举结果时,如果数据发生变化,您将得到不同的结果。

a) 但从下面的代码可以看出,即使不使用延迟查询,我们也能够实现相同的效果(因此每次枚举资源时,如果数据发生更改,我们会得到不同的结果):

List<string> sList = new List<string>( new[]{ "A","B" });

foreach (string item in sList)
    Console.WriteLine(item); // Q1 outputs AB

sList.Add("C");

foreach (string item in sList)
    Console.WriteLine(item); // Q2 outputs ABC

3)延迟执行还有其他好处吗?


主要好处是,这使得 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);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LINQ 中的延迟执行有什么好处? 的相关文章