LINQ IEnumerable<T> 内存结构

5
我知道在 C# 中,最常见的集合都实现了 IEnumerable 接口:List、T[] 和 Dictionary。
然而,当你运行像这样的 LINQ 查询时:
myCol.Where(myBoolMethod);
你会得到一个未知类型的数据,该数据实现了 IEnumerable 接口。
因此,我想知道这些数据在被转换成更有用的格式(如 .ToList()、.ToArray() 等)之前,其实际存储方式是什么?
它是否仍保持在源类型中?它是否被存储在伪数组中?还是一种以上两种方式的组合?
此外,无论涉及哪些数据类型,将数据转换为 IEnumerable 的某一种类型是否总是比转换为另一种类型更快,即 myCol.Where(myBoolMethod).ToArray() 比 myCol.Where(myBoolMethod).ToList() 总是更快?

1
https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs - Jakub Lortz
4个回答

5
它并没有被存储。它代表了在以后的时间点上获取数据的能力,但是数据本身仍然潜藏在原始集合中,LINQ查询已经被组合。(以及任何存在于表达式中创建新值的逻辑)
这就是为什么有各种警告不要存储这些结果,除非使用ToXxx方法,如果有任何可能导致查询多次执行的情况。

啊,这样就清楚多了,谢谢。除非有更好的答案出现,否则一旦时间限制过去我就会接受这个答案。 - ScottishTapWater

3
它是否保留在源类型中?它是否存储在伪数组中?还是以上两者的某种组合?
大多数LINQ扩展方法每次访问生成的IEnumerable时都会遍历源(这称为延迟执行)。通常不会将结果存储在中间源中。
是否有任何原因,从一种类型的IEnumerable转换到另一种类型的IEnumerable始终比从其他类型转换更快?
是的,调用ToArray或ToList将执行可枚举并使其实现。如果您不使用返回的IEnumerable,则不会使其实现。性能影响约为0。

0

0
当你执行myCol.Where(myBoolMethod)时,数据实际上并没有被枚举。它不会存储在数组或其他任何地方,你只是得到了一个枚举器,它让你枚举这个集合。
当你执行.ToArray()时,它实际上使用枚举器来创建一个新的数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接