如何实现识别迭代器的编译器?

时间:2009-07-13 07:46:11

标签: iterator compiler-construction yield-keyword

我一直在使用迭代器,我喜欢它们。

但是虽然我一直在努力思考它,但我无法弄清楚“如何识别迭代器的编译器”。我也研究过它,但找不到任何资源来解释编译器设计环境中的情况。

详细说明,大多数关于迭代器的文章暗示存在某种实现所需行为的“魔法”。他们建议编译器维护一个状态机,以便跟踪执行的位置(可以看到最后一次'yield return')。我对迭代器的这个属性特别感兴趣,可以进行惰性求值。

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

感谢任何知识或差异化的想法。

2 个答案:

答案 0 :(得分:5)

它比看起来更简单。编译器可以将迭代器函数分解为单个块;块被yield语句划分。

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

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

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

Eric Lippert发布​​了in-depth description这个过程。(阅读他所链接的文章!)

答案 1 :(得分:1)

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

但是,我对这些事情并不是很了解,所以也许我完全错了。