Linq推迟运营

hau*_*ous 5 .net c# linq

我主要理解延迟执行,但我对特定情况有疑问:

给定一个代码片段,如

                        var resultsOfInterest = from r in ...
                                                select r;
                        foreach (var x in resultsOfInterest)
                        {
                            //do something with x
                        }
Run Code Online (Sandbox Code Playgroud)

查询resultsOfInterest 执行了多少次?一旦设置foreach循环,或每个元素'x'一次?是否会更有效率

                        foreach (var x in resultsOfInterest.ToArray())
                        {
                            //do something with x
                        }
Run Code Online (Sandbox Code Playgroud)

TIA

Ser*_*kiy 5

它将在循环之前执行一次,当GetEnumerator()方法将在查询变量上执行时.以下是foreach循环的样子:

var enumerator = resultsOfInterest.GetEnumerator(); // query executed here

while(enumerator.MoveNext()) // iterating over results of query execution
{
   var x = enumerator.Current;
   // do something with x
}
Run Code Online (Sandbox Code Playgroud)

第二个样本效率不高,它只是将查询执行结果存储在数组中,然后调用数组迭代器:

var enumerator = resultsOfInterest.ToArray().GetEnumerator();
// loop stays same
Run Code Online (Sandbox Code Playgroud)


p.s*_*w.g 3

在这两种情况下,它只运行一次。

在第一个示例中(如果这是 Linq-to-Objects 查询),它运行的时间足以x在每次迭代中获取下一个查询。在第二个示例中,它必须立即计算整个结果集并将其存储到数组中。

因此,假设这是一个昂贵的查询,获取每个项目需要 1 秒,并且列表中有 20 个项目,两个查询将花费大约 20 秒来处理所有项目。但是,第一个在每次迭代中获取下一个项目时将被阻塞 1 秒,但第二个将在循环开始之前被阻塞 20 秒,然后相当快地循环遍历数组中的所有项目。

在实际评估查询时,两者都没有更有效。但是,一般来说,您应该避免不必要的调用ToArrayor ToList,因为除了评估查询之外,它还必须为结果分配一个数组(List<T>将其项目存储在内部数组中)。对于包含 20 个项目的列表,这意义不大,但当您有数千个项目时,这可能会导致速度明显减慢。当然,这并不意味着这ToArray总是不好。如果在前面的示例中有 5 个foreach循环,则将结果存储在数组中并循环遍历该数组,而不是每次都重新评估查询,实际上会使代码速度加快约 80 秒