如何枚举LINQ查询?

时间:2009-09-22 22:32:00

标签: vb.net linq

一开始这似乎是一个愚蠢的问题,但请继续阅读。

我知道LINQ查询是延迟的,只有在枚举查询时才会执行,但我无法确切知道何时发生这种情况。当然在For Each循环中,将枚举查询。遵循的经验法则是什么?如果这是一个巨大的结果,我不想两次意外地枚举我的查询。

例如,System.Linq.Enumerable.First是否枚举整个查询?我要求性能原因。我想将LINQ结果集传递给ASP.NET MVC视图,我也想分别传递First元素。对结果进行两次计算会很痛苦。

每次枚举LINQ查询时,打开某种警告我会很棒。这样,当我偶然两次枚举时,我可以捕捉到场景。

2 个答案:

答案 0 :(得分:8)

您可以add your own logging轻松地查看正在发生的事情。除此之外,懒惰/急切位相当清楚。基本上它可以是懒惰的 - 任何时候返回类型都是IEnumerable<T>IOrderedEnumerable<T>。这些人可能很懒,因为你无法在不调用GetEnumerator()的情况下获取任何数据。例如,将它与First()进行比较 - 它必须为您返回一个值。它不能推迟任何事情。

一般来说,如果您想确保不会多次评估查询,请在其上调用ToListToArray,然后多次使用该结果。同样,这些方法必须立即返回列表或数组,这两者都不允许延迟填充。查询被评估,但是它实际上与生成的填充集合断开连接 - 查询将不会再次执行,无论您检查列表多少。

除了懒惰/急切的问题,还有流媒体/非流媒体:该方法会从源可读的所有内容中读取所有内容,还是只是“啜饮”它,并在需要时进行读取。同样,一般情况下LINQ只会在必要时读取 - 所以虽然Reverse是非流式传输(但仍然是懒惰的),WhereSelect正在流式传输。

答案 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。