いいえ-それからはほど遠いです。長文バージョンを書きます... 汚すぎます!
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()
- につながるコードの部分
yield return
(case
大まかに)
yield break
state = -1; return false;
(または同様の) になります
C# コンパイラがこれを行う方法は非常に複雑ですが、イテレータを簡単に記述できます。