5

我主要了解延迟执行,但我有一个关于特定案例的问题:

给定一个代码片段,例如

                        var resultsOfInterest = from r in ...
                                                select r;
                        foreach (var x in resultsOfInterest)
                        {
                            //do something with x
                        }

查询resultsOfInterest执行了多少次 ?设置foreach循环时一次,还是每个元素“x”一次?会更有效吗

                        foreach (var x in resultsOfInterest.ToArray())
                        {
                            //do something with x
                        }

?

TIA

4

3 回答 3

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
}

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

var enumerator = resultsOfInterest.ToArray().GetEnumerator();
// loop stays same
于 2013-09-04T14:21:00.193 回答
3

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

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

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

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

于 2013-09-04T14:21:13.183 回答
0

在这两种情况下,查询只执行一次,但在第二种情况下,有两个枚举

假设有 1000 个项目:

情况1:

  1. 执行select子句,将结果分配给x.
  2. 转到 1,重复 1000 次。

案例二:

  1. 创建数组。
  2. 执行select子句,将结果分配给数组。
  3. 转到 2,重复 1000 次。
  4. 访问数组中的元素,将其分配给x.
  5. 转到 4,重复 1000 次。

因此,通常根本不需要创建数组。但是如果您需要自己多次枚举相同的项目,并且数组访问速度比您的要快select,那么创建数组当然会更有效。

于 2013-09-04T15:13:45.270 回答