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?
现在,LINQ的延迟执行,将后续的foreach循环执行查询一次或在循环中的每个转弯?
是的,一旦循环。 实际上,它可以执行查询不止一次少-你可以通过中止循环部分的方式和(num % 2) == 0
的测试不会对任何剩余的项目进行。
或者,换句话说,会不会有什么区别,如果我有:
foreach (int num in numQuery.ToList())
两点不同:
在上述情况下, ToList()
浪费时间和存储器的,因为它首先做同样的事情作为初始foreach
,从它建立一个列表,然后foreach
s表示列表。 的差异,将是微不足道的地方,防止代码从以往的工作,根据结果的大小之间。
然而,在你要反复做的情况下foreach
上相同的结果,否则反复使用,当时同时foreach
只运行一次查询,接下来foreach
再次运行它。 如果查询是昂贵的,那么ToList()
方法(和存储该列表)可以是一个巨大的节省。
不,这都没有区别。 在in
表达式计算一次。 更具体地, foreach
构建调用GetEnumerator()
的方法in
表达及反复调用MoveNext()
并且访问Current
为了遍历属性IEnumerable
。
OTOH,调用ToList()
是多余的。 不应该去调用它。
如果输入的是一个数据库,情况稍有不同,因为LINQ输出IQueryable
,但我敢肯定foreach
仍然将其视为IEnumerable
(这IQueryable
继承)。
按照规定,每次循环会因为它需要获取下一个结果做完全一样多的工作。 因此,答案将在技术上是“以上都不是”。 查询会“在片”执行。
如果你使用ToList()
或任何其他实现方法( ToArray()
等),那么查询将被当场和后续操作(如遍历结果)评估一次将只是一个“哑”名单上的工作。
如果numbers
是一个IQueryable
,而不是IEnumerable
-因为它很可能是数据库中的场景-那么,上述仍接近真相虽然不是一个完全准确的描述。 特别是,在第一次尝试兑现的结果,可查询的提供者将谈论到数据库,并产生一个结果集; 那么,从这个结果集中的行会在每次迭代拉。
当枚举LINQ查询将被执行(作为结果.ToList()
调用或做foreach
以上的结果。
如果你列举LINQ查询的结果两次,两次将导致它来查询数据源(在你的榜样,枚举集),因为它本身只返回一个IEnumerable
。 但是,根据LINQ查询,它可能并不总是枚举整个集合(例如.Any()
和.Single()
将停止第一对象或第一个匹配的对象上,如果有一个.Where()
一个LINQ提供程序的实现细节可能有所不同,因此通常的行为时,数据源是一个数据库调用.ToList()
马上到cache
的查询结果和也保证了查询(在EF,L2S的情况下,或NHibernate的)当集合在某一点在后面的代码枚举并防止被执行多次,如果结果列举多次查询被执行一次那里,然后 ,而不是。