yield break; - 疯狂的行为

6
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main (string[] args)
        {
            var test1 = Test1(1, 2);
            var test2 = Test2(3, 4);
        }

        static IEnumerable Test1(int v1, int v2)
        {
            yield break;
        }

        static IEnumerable Test2 (int v1, int v2)
        {
            return new String[] { };
        }
    }
}

"test1" 似乎是一个 IEnumerable,其中 v1 和 v2(参数)作为字段,而 "Test1" 没有被调用。

"Test2" 工作得很“完美” :)

发生了什么?

2个回答

15

Test1被调用了,但是除非你迭代结果,否则你不会在yield break上触发断点。

基本上,Test1被转换为一个实现IEnumerable的状态机... 但是,你方法中的所有代码都在状态机内部,除非你通过调用GetEnumerator()MoveNext()(或使用foreach循环)来使用状态机,否则你看不到方法体执行。

更多信息,请参见我的通用迭代器文章和我的迭代器实现文章,以及Eric Lippert的两篇博客文章:心灵调试第一部分心灵调试第二部分


1

既然你提到了Python,我要指出Python中的生成器与C#中的生成器非常相似。只有一个小区别,就是在C#中,yield break可以将一个方法转换为生成器,而Python中等效的raise StopIteration则不行。

>>> def f():
...     print "Beginning of generator"
...     if False: yield
...     print "End of generator"
... 
>>> it = f()
>>> it
<generator object at 0x94fae2c>
>>> it.next()
Beginning of generator
End of generator
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

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