C#で、
public class MyClass {
public IEnumerable<int> GetEnumerator() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}
}
というコードを書けば、
MyClass mc = new MyClass();
foreach ( int i in mc.GetEnumerator() ) {
Console.WriteLine(i);
}
と foreach 文が書ける。最も手軽な反復子の書き方だ。
でも、2つのメソッドで、値を順に取り出したいときなどforeach 文 が使えない場面もある。
こんなときは、MoveNext(), Current メソッド使うのだが、ちょっと、困った。
IEnumerator<int> e = mc.GetEnumerator().GetEnumerator();
while ( e.MoveNext() ) {
Console.WriteLine(e.Current);
}
これで、一応目的は達したのだが、GetEnumerator().GetEnumerator();
という部分は、何かおかしい。
そもそも、IEnumerable<> を返しているのに、GetEnumerator() という名前をつけていることが変だ。
やはり、
public IEnumerable<int> GetEnumerable() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}
と GetEnumerable() が良さそうだ。
でも、
GetEnumerable を Google で日本語のページを検索すると、たった数件しかヒットしない。
何でだろう?
よくよく考えたら、戻り値が、IEnumerableの方を直すべきだった。GetEnumerator()なんだから、IEnumerator を返すメソッドにしないとね。
お二人のコメントで、foreach についてあやふやだったことが、だいぶ整理できてきました。Thanks! です。
foreachは、IEnumerableインターフェースを実装していることが前提だったと思ったのですが、IEnumerableを実装していなくても、GetEnumerator()メソッドを実装していれば、foreachを受け付けてくれるように変更されていたんですね。(それとも最初から?)
そのため、static メソッドでは、IEnumerableを返す必要がある。
いっぽう、インスタンスメソッドでは、IEnumerableを実装する、しないにかかわらず、GetEnumerator()を実装していさえすれば、
MyClass obj = new MyClass();
foreach (object o in obj) {
...
}
と書ける。
ただ、逆順をたどるような反復子も用意したい場合には、GetEnumrator()という名前は使えないので、IEnumrator を返すメソッドを書いても、エラーになる。
IEnumerableを返すメソッドにしなければならない。
ってことですね。
http://msdn2.microsoft.com/ja-jp/library/9yb8xew9(VS.80).aspx
には、
----
インターフェイスを省略すると、Current の戻り値の型を object よりも明確に定義できるので、結果としてタイプ セーフになります。
----
と書いてあります。ふーん、そうなんだ。