一开始这似乎是一个愚蠢的问题,但请继续阅读。
我知道LINQ查询是延迟的,只有在枚举查询时才会执行,但我无法确切知道何时发生这种情况。当然在For Each循环中,将枚举查询。遵循的经验法则是什么?如果这是一个巨大的结果,我不想两次意外地枚举我的查询。
例如,System.Linq.Enumerable.First是否枚举整个查询?我要求性能原因。我想将LINQ结果集传递给ASP.NET MVC视图,我也想分别传递First元素。对结果进行两次计算会很痛苦。
每次枚举LINQ查询时,打开某种警告我会很棒。这样,当我偶然两次枚举时,我可以捕捉到场景。
答案 0 :(得分:8)
您可以add your own logging轻松地查看正在发生的事情。除此之外,懒惰/急切位相当清楚。基本上它可以是懒惰的 - 任何时候返回类型都是IEnumerable<T>
或IOrderedEnumerable<T>
。这些人可能很懒,因为你无法在不调用GetEnumerator()
的情况下获取任何数据。例如,将它与First()
进行比较 - 它必须为您返回一个值。它不能推迟任何事情。
一般来说,如果您想确保不会多次评估查询,请在其上调用ToList
或ToArray
,然后多次使用该结果。同样,这些方法必须立即返回列表或数组,这两者都不允许延迟填充。查询被评估,但是它实际上与生成的填充集合断开连接 - 查询将不会再次执行,无论您检查列表多少。
除了懒惰/急切的问题,还有流媒体/非流媒体:该方法会从源可读的所有内容中读取所有内容,还是只是“啜饮”它,并在需要时进行读取。同样,一般情况下LINQ只会在必要时读取 - 所以虽然Reverse
是非流式传输(但仍然是懒惰的),Where
和Select
正在流式传输。
答案 1 :(得分:5)
对于何时枚举LINQ查询以及何时不进行查询,没有严格的规则。部分原因是某些方法将会或不会基于查询源的基础类型。
这是一个快速分解。这绝不是一个彻底的分解,主要是我在5分钟内想出来的。
他们完全立即枚举列表。它们通常由返回标量值的扩展方法发现。例如Sum,Min,Max,Count,Last等......
注意:Count和Last不一定要枚举整个列表。如果基础类型可转换为ICollection<T>
,则它们将使用更有效的方法。
他们只查看列表的第一个元素,可能是第二个元素。它们是First,FirstOrDefault,Single,SingleOrDefault。
以上是引用不带谓词的版本。如果他们采用谓词,他们更好地归类为查询(见下文)
他们只会枚举执行操作所需的最小数量的列表。这可以是1个元素,也可以是整个列表的数量。
示例:Any,Contains
这是LINQ中的绝大多数运营商。枚举新列表时会产生成本。示例:选择,Where,Group,Join,SkipWhile,Skip。