4

我使用迭代器已经有一段时间了,我喜欢它们。

但是,尽管我仔细考虑过,但我无法弄清楚“如何实现识别迭代器的编译器”。我也对此进行了研究,但找不到任何资源来解释编译器设计上下文中的情况。

详细地说,大多数关于迭代器的文章都暗示有某种“魔法”来实现所需的行为。他们建议编译器维护一个状态机,以便跟踪执行的位置(看到最后一个“收益返回”的位置)。我对启用惰性求值的迭代器的这个属性特别感兴趣。

顺便说一句,我知道什么是状态机,已经上过编译器设计课程,研究过龙之书。但显然,我无法将我所研究的内容与 csc 的“魔法”联系起来。

任何知识或不同的想法都会受到赞赏。

4

2 回答 2

5

它比看起来更简单。编译器可以将迭代器函数分解成单独的块;块由yield语句划分。

状态机只需要跟踪我们当前所在的块,并在下一次调用迭代器时直接跳转到该块。我们还需要跟踪所有局部变量(当然)。

然后,我们需要考虑一些特殊情况,特别是包含yields 的循环。幸运的是,IL(但不是 C# 本身)允许goto跳入循环恢复它们。

请注意,有一些非常复杂的边缘情况,例如 C# 不允许yieldinfinally块,因为将函数留在上面会非常困难(不可能?)yield,然后恢复函数,执行清理,重新抛出任何异常保留堆栈跟踪。

Eric Lippert 发布了对该过程的深入描述(也请阅读他链接到的文章!)

于 2009-07-13T09:00:47.010 回答
1

我会尝试的一件事是用 C# 编写一个简短的示例,对其进行编译,然后在其上使用 Reflector。我认为这个“yield return”只是语法糖,所以你应该能够在反汇编器的输出中看到编译器是如何处理它的。

但是,好吧,我对这些事情知之甚少,所以也许我完全错了。

于 2009-07-13T08:59:35.813 回答