IEnumerable<T>型のメソッドを定義して、その処理中に yield return 値; を記述することで、IEnumerable<T>オブジェクトを生成することができる。
IEnumerable<int> MyEnumerable() { 処理; yield return 値; 処理; }
この方法を利用したほうが、IEnumerable<T>型やIEnumerator<T>型のクラスを定義するよりも簡単にEnumeratorが作成できる。
試しにforech文を使用せずに、GetEnumerator()メソッドでIEnumerator<T>型オブジェクトを取得したところ、GetNext()メソッドおよびCurrentプロパティで値を順番に取得することができた。
yield returnを使用した場合の動作は、IEnumerable<T>型のメソッド中でyield return文に出くわすと、foreach側に制御が移ってforeachブロックの処理を実行する。その処理が終了すると再びIEnumerable<T>型のメソッドに制御が移りyield return文の次から処理が行われるという形になる。これがIEnumerable<T>型のメソッドの処理が終了するまで継続する。
using System; using System.Collections.Generic; //yield class OtherClass { public IEnumerable<int> OtherIEnumerable() { for(var i = 10; i < 15; i++) { yield return i; } } } class MyMain { public static void Main(string[] args) { //自クラスのstaticメソッドを使用 foreach(var e in MyEnumerable()) { Console.WriteLine("Main foreach内:値 {0} ", e); } Console.WriteLine("-----"); //foreachを使用せずに読み出す var menumerable = MyEnumerable(); var me = menumerable.GetEnumerator(); bool b; b = me.MoveNext(); Console.WriteLine( "MoveNext()実行: {0}", b ); if( b ) Console.WriteLine( "Current取得 : {0}", me.Current ); b = me.MoveNext(); Console.WriteLine( "MoveNext()実行: {0}", b ); if( b ) Console.WriteLine( "Current取得 : {0}", me.Current ); Console.WriteLine("-----"); //他クラスのインスタンスメソッドを使用 var oe = new OtherClass(); foreach(var e in oe.OtherIEnumerable()) { Console.Write("{0} ", e); } Console.WriteLine(); Console.WriteLine("-----"); //自クラスのstaticメソッド(非ループ)を使用 foreach(var e in MyEnumerable2()) { Console.Write("{0} ", e); } Console.WriteLine(); Console.WriteLine("-----"); } //ループ処理 public static IEnumerable<int> MyEnumerable() { for(var i = 0; i < 5; i++) { Console.WriteLine("MyEnumerable内:yield前:値 {0}", i); yield return i; Console.WriteLine("MyEnumerable内:yield後:値 {0}", i); } } //非ループ(yieldが複数個存在) public static IEnumerable<int> MyEnumerable2() { yield return 100; yield return 200; yield return 300; } }
実行結果
MyEnumerable内:yield前:値 0 Main foreach内:値 0 MyEnumerable内:yield後:値 0 MyEnumerable内:yield前:値 1 Main foreach内:値 1 MyEnumerable内:yield後:値 1 MyEnumerable内:yield前:値 2 Main foreach内:値 2 MyEnumerable内:yield後:値 2 MyEnumerable内:yield前:値 3 Main foreach内:値 3 MyEnumerable内:yield後:値 3 MyEnumerable内:yield前:値 4 Main foreach内:値 4 MyEnumerable内:yield後:値 4 ----- MyEnumerable内:yield前:値 0 MoveNext()実行: True Current取得 : 0 MyEnumerable内:yield後:値 0 MyEnumerable内:yield前:値 1 MoveNext()実行: True Current取得 : 1 ----- 10 11 12 13 14 ----- 100 200 300 -----