的foreach是否执行查询只有一次?(Does foreach execute the query

2019-07-03 14:34发布

I have a list of items and a LINQ query over them. Now, with LINQ's deferred execution, would a subsequent foreach loop execute the query only once or for each turn in the loop?

Given this example (Taken from Introduction to LINQ Queries (C#), on MSDN)

    // The Three Parts of a LINQ Query: 
    //  1. Data source. 
    int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

    // 2. Query creation. 
    // numQuery is an IEnumerable<int> 
    var numQuery =
        from num in numbers
        where (num % 2) == 0
        select num;

    // 3. Query execution. 
    foreach (int num in numQuery)
    {
        Console.Write("{0,1} ", num);
    }

Or, in other words, would there be any difference if I had:

    foreach (int num in numQuery.ToList())

And, would it matter, if the underlying data is not in an array, but in a Database?

Answer 1:

现在,LINQ的延迟执行,将后续的foreach循环执行查询一次或在循环中的每个转弯?

是的,一旦循环。 实际上,它可以执行查询不止一次少-你可以通过中止循环部分的方式和(num % 2) == 0的测试不会对任何剩余的项目进行。

或者,换句话说,会不会有什么区别,如果我有:

foreach (int num in numQuery.ToList())

两点不同:

  1. 在上述情况下, ToList()浪费时间和存储器的,因为它首先做同样的事情作为初始foreach ,从它建立一个列表,然后foreach s表示列表。 的差异,将是微不足道的地方,防止代码从以往的工作,根据结果的大小之间。

  2. 然而,在你要反复做的情况下foreach上相同的结果,否则反复使用,当时同时foreach只运行一次查询,接下来foreach再次运行它。 如果查询是昂贵的,那么ToList()方法(和存储该列表)可以是一个巨大的节省。



Answer 2:

不,这都没有区别。 在in表达式计算一次。 更具体地, foreach构建调用GetEnumerator()的方法in表达及反复调用MoveNext()并且访问Current为了遍历属性IEnumerable

OTOH,调用ToList()是多余的。 不应该去调用它。

如果输入的是一个数据库,情况稍有不同,因为LINQ输出IQueryable ,但我敢肯定foreach仍然将其视为IEnumerable (这IQueryable继承)。



Answer 3:

按照规定,每次循环会因为它需要获取下一个结果做完全一样多的工作。 因此,答案将在技术上是“以上都不是”。 查询会“在片”执行。

如果你使用ToList()或任何其他实现方法( ToArray()等),那么查询将被当场和后续操作(如遍历结果)评估一次将只是一个“哑”名单上的工作。

如果numbers是一个IQueryable ,而不是IEnumerable -因为它很可能是数据库中的场景-那么,上述仍接近真相虽然不是一个完全准确的描述。 特别是,在第一次尝试兑现的结果,可查询的提供者将谈论到数据库,并产生一个结果集; 那么,从这个结果集中的行会在每次迭代拉。



Answer 4:

当枚举LINQ查询将被执行(作为结果.ToList()调用或做foreach以上的结果。

如果你列举LINQ查询的结果两次,两次将导致它来查询数据源(在你的榜样,枚举集),因为它本身只返回一个IEnumerable 。 但是,根据LINQ查询,它可能并不总是枚举整个集合(例如.Any().Single()将停止第一对象或第一个匹配的对象上,如果有一个.Where()

一个LINQ提供程序的实现细节可能有所不同,因此通常的行为时,数据源是一个数据库调用.ToList()马上到cache的查询结果和也保证了查询(在EF,L2S的情况下,或NHibernate的)当集合在某一点在后面的代码枚举并防止被执行多次,如果结果列举多次查询被执行一次那里,然后 ,而不是。



文章来源: Does foreach execute the query only once?
标签: c# linq tolist