为什么 linq to object 手动实现迭代器?

Why is linq to object implementing iterators manually?

在浏览 .net 核心源代码时,我注意到即使在源代码形式中,迭代器 类 也是手动实现的,而不是依赖于 yield 语句和自动 IEnumerable 实现。

例如,您可以在这一行看到 where 迭代器的声明和实现 https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Enumerable.cs#L168

我假设如果他们经历了这样做的麻烦而不是简单的 yield 语句,那肯定会有一些好处,但我不能立即看到哪个,它看起来与我记得的编译器所做的非常相似几年前我自动回读了 eric lippert 的博客,我记得在早期我天真地用 yield 语句重新实现 LINQ 以更好地理解它,性能配置文件与 .NET 版本相似。

这激起了我的好奇心,但这也是一个非常重要的问题,因为我正处于一个相当大的数据 - 在内存项目中,如果我遗漏了一些明显的东西,使这种方法更好,我很想知道权衡。

编辑:澄清一下,我明白为什么他们不能只在 where 方法中产生(不同容器类型的不同枚举),我不明白的是为什么他们自己实现迭代器(即,而不是分叉到不同的迭代器,分叉到不同的方法,基于类型进行不同的迭代,并产生自动实现的状态机而不是手动情况 1 转到 2 情况 2 等)。

一个可能的原因是专用迭代器执行了一些优化,例如组合选择器和谓词以及利用索引集合。

这些的用处在于,一些源可以以比 yield 的编译器魔术生成的更优化的方式进行迭代。通过创建这些自定义迭代器,他们可以将关于源的这些额外信息传递给单个链中的后续 LINQ 操作(而不是使该信息仅对链中的第一个操作可用)。因此,所有 WhereSelect 操作(它们之间没有任何其他操作)可以作为一个执行。