【发布时间】:2013-06-01 12:34:24
【问题描述】:
我第一次使用 .NET 中的实体框架,并且一直在编写 LINQ 查询以从我的模型中获取信息。我想从一开始就养成良好的编程习惯,所以我一直在研究编写这些查询的最佳方法,并得到它们的结果。不幸的是,在浏览 Stack Exchange 时,我似乎遇到了关于延迟/立即执行如何与 LINQ 一起工作的两种相互矛盾的解释:
- foreach 导致在循环的每次迭代中执行查询:
在问题Slow foreach() on a LINQ query - ToList() boosts performance immensely - why is this? 中显示,这意味着需要调用“ToList()”才能立即评估查询,因为 foreach 正在重复评估数据源上的查询,从而大大减慢了操作速度。
另一个例子是问题 Foreaching through grouped linq results is incredibly slow, any tips? ,其中接受的答案还暗示在查询上调用“ToList()”将提高性能。
- foreach 会导致查询执行一次,并且可以安全地与 LINQ 一起使用
在问题Does foreach execute the query only once?中演示,意思是foreach导致一个枚举建立,不会每次都查询数据源。
继续浏览该网站发现了许多问题,其中“在 foreach 循环期间重复执行”是性能问题的罪魁祸首,还有许多其他答案表明 foreach 将适当地从数据源中获取单个查询,这意味着这两种解释似乎都有效。如果“ToList()”假设不正确(截至 2013 年 6 月 5 日下午 1:51 EST 的大多数当前答案似乎暗示),这种误解来自哪里?这些解释中是否有一种准确而另一种不准确,或者是否存在可能导致 LINQ 查询评估不同的不同情况?
编辑:除了下面接受的答案之外,我在 Programmers 上提出了以下问题,这非常有助于我理解查询执行,特别是可能导致多个数据源命中的陷阱循环,我认为这对其他对此问题感兴趣的人会有所帮助:https://softwareengineering.stackexchange.com/questions/178218/for-vs-foreach-vs-linq
【问题讨论】:
-
我想这取决于 foreach 中的查询实际上在做什么。
-
foreach通常是与IEnumerable/IQueryable一起使用时出现性能问题的罪魁祸首。 -
我们真的需要一个非常具体的例子才能正确地推理它。
foreach只会调用GetEnumerator一次...但是如果您多次执行整个foreach循环,它将多次调用GetEnumerator... -
链接的问题是可疑的,我不相信那里接受的答案。
-
回答编辑过的问题:这与 foreach 无关,而与延迟执行 LINQ 无关。如果您反复使用
.Contains()、.First()、.Single()或其他任何导致 LINQ 执行的东西,您会遇到完全相同的问题。对于对象,这无关紧要,但对于数据库查询,它确实如此。调用ToList()将查询(如果是一个)转换为对象,因此以后使用不需要命中数据库。