了解迭代器块和处理方法

时间:2009-12-09 09:27:28

标签: c# iterator

我正在观看Jon Skeet的Copenhagen C# talk视频,我最终得到了这段代码。
问题:
代码打印完成后发生了什么。我的意思是为什么 iterator.MoveNext() 失败?

CODE:

 class IteratorBlocks
    {
        public static IEnumerable<string> GetStringsForever()
        {
            string current = "";
            char nextChar = 'a';
            try
            {
                while (true)
                {
                    current += nextChar;
                    nextChar++;

                    if (nextChar > 'z')
                    {
                        nextChar = 'a';
                    }

                    yield return current;
                }
            }
            finally
            {
                Console.WriteLine("Finished");
            }
        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            IEnumerable<string> strings = IteratorBlocks.GetStringsForever();

            IEnumerator<string> iterator = strings.GetEnumerator();

            for (int i = 0; i < 10; i++)
            {
                iterator.MoveNext();
                Console.WriteLine(iterator.Current);
            }

            /* 
               I am not able to get what the code is doing beyond this line?
             */

            iterator.Dispose();

            for (int i = 0; i < 10; i++)
            {
                iterator.MoveNext();
                Console.WriteLine(iterator.Current);
            }

        }
    }

OUTPUT:

a
ab
abc
abcd
abcde
abcdef
abcdefg
abcdefgh
abcdefghi
abcdefghij
Finished
abcdefghij
abcdefghij
abcdefghij
abcdefghij
abcdefghij
abcdefghij
abcdefghij
abcdefghij
abcdefghij
abcdefghij

3 个答案:

答案 0 :(得分:7)

调用MoveNext()只会返回false而不做任何其他事情,因为你已经处理了迭代器。由C#编译器构建的状态机将进入“后”状态,并保持在那里。有关详细信息,请参阅C#3规范的第10.14.4.2节。

Current属性将继续返回它返回的最后一个值 - 这种情况下的行为是explicitly undefined in MSDN。 (我本可以发誓这是为了抛出异常,但显然不是。)

这有意义吗? Dispose不会“重置”迭代器(并且C#迭代器块不支持Reset方法本身)。如果您想再次进行迭代,则需要再次调用GetEnumerator

现在,我不记得我在哥本哈根会谈中所说的具体内容,如果其中任何一个看起来与视频所显示的相反,请道歉:)

答案 1 :(得分:1)

当您使用.NET的迭代器模式和yield return时,您将获得一个为您构建的小型状态机。调用dispose会将状态机移动到最终状态。在最终状态中,迭代器将不再向前移动,但它将记住它的最后状态(当前)。如果你看一下生成的IL(或者可能通过Reflector,还没有尝试过),它就变得非常清楚了。

答案 2 :(得分:0)

如果你继续处理被处置的物体,就会发生奇怪的事情!