不——远非如此;我给你写个长手版……太邋遢了!
请注意,如果您了解foreach
实际情况,它也会有所帮助:
using(var iterator = YieldDemo.SupplyIntegers().GetEnumerator()) {
int i;
while(iterator.MoveNext()) {
i = iterator.Current;
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
static class Program
{
static void Main()
{
foreach (int i in YieldDemo.SupplyIntegers())
{
Console.WriteLine("{0} is consumed by foreach iteration", i);
}
}
}
class YieldDemo
{
public static IEnumerable<int> SupplyIntegers()
{
return new YieldEnumerable();
}
class YieldEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new YieldIterator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
class YieldIterator : IEnumerator<int>
{
private int state = 0;
private int value;
public int Current { get { return value; } }
object IEnumerator.Current { get { return Current; } }
void IEnumerator.Reset() { throw new NotSupportedException(); }
void IDisposable.Dispose() { }
public bool MoveNext()
{
switch (state)
{
case 0: value = 1; state = 1; return true;
case 1: value = 2; state = 2; return true;
case 2: value = 3; state = 3; return true;
default: return false;
}
}
}
}
如您所见,它在迭代器中构建了一个状态机,状态机前进了MoveNext
. 我已经将模式与state
字段一起使用,您可以看到这对于更复杂的迭代器是如何工作的。
重要的:
- 迭代器块中的任何变量都成为状态机上的字段
- 如果你有一个
finally
块(包括using
),它会进入Dispose()
- 导致 a
yield return
变成 a 的部分代码case
(大致)
yield break
成为state = -1; return false;
(或类似的)
C# 编译器执行此操作的方式非常复杂,但它使编写迭代器变得轻而易举。