C#のyieldキーワードの2セント

C#2.0で最初に導入されたyieldキーワードTは、IEnumerableインターフェイスを実装するオブジェクトを返します。IEnumerableインターフェイスは、C#のforeachループを使用して非ジェネリックコレクションを反復処理するために使用できるIEnumeratorを公開します。yieldキーワードを使用して、メソッドまたはそれが使用されているgetアクセサーがイテレーターであることを示すことができます。

yieldキーワードを使用する方法は2つあります。「yieldreturn」ステートメントと「yieldbreak」ステートメントを使用する方法です。両方の構文を以下に示します。

yield return ;

yield break;

なぜyieldキーワードを使用する必要があるのですか?

yieldキーワードは、一時的なコレクションを作成する必要がなく、状態全体の反復を実行できます。つまり、イテレータ内で「yield return」ステートメントを使用する場合、データが返される前にデータを格納するための一時的なコレクションを作成する必要はありません。yield returnステートメントを利用して、コレクション内の各要素を一度に1つずつ返すことができます。また、メソッドまたはgetアクセサーのイテレーターで「yieldreturn」ステートメントを使用できます。

「yieldreturn」ステートメントが検出されて実行されるたびに、コントロールが呼び出し元に返されることに注意してください。最も重要なことは、そのような呼び出しごとに、呼び出し先の状態情報が保持されるため、コントロールが戻ったときに、yieldステートメントの直後に実行を続行できます。

例を見てみましょう。次のコードスニペットは、yieldキーワードを使用してフィボナッチ数を返す方法を示しています。このメソッドは、生成するフィボナッチ数の数を表す整数を引数として受け入れます。

static IEnumerable GenerateFibonacciNumbers(int n)

       {

           for (int i = 0, j = 0, k = 1; i < n; i++)

          {

               yield return j;

               int temp = j + k;

               j = k;

               k = temp;

           }

       }

上記のコードスニペットに示されているように、ステートメント「yieldreturnj;」「for」ループを終了せずに、フィボナッチ数を1つずつ返します。つまり、状態情報が保持されます。GenerateFibonacciNumbersメソッドを呼び出す方法は次のとおりです。

foreach (int x in GenerateFibonacciNumbers(10))

   {

       Console.WriteLine(x);

   }

お気づきのように、生成して呼び出し元に返す必要のあるフィボナッチ数を保持するために、中間リストまたは配列を作成する必要はありません。

カバーの下で、yieldキーワードは、状態情報を維持するためのステートマシンを作成することに注意してください。MSDNは次のように述べています。「イテレータメソッドでyieldreturnステートメントに到達すると、式が返され、コード内の現在の場所が保持されます。次にイテレータ関数が呼び出されたときに、その場所から実行が再開されます。」

yieldキーワードを使用するもう1つの利点は、返されるアイテムがオンデマンドでのみ作成されることです。例として、次のgetアクセサーは1から10までの偶数を返します。

public static IEnumerable EvenNumbers

       {{

           取得する

           {{

               for(int i = 1; i <= 10; i ++)

               {{

                   if((i%2)== 0)

                   イールドリターンi;

               }

           }

       }

以下のコードスニペットを使用して、EvenNumbers静的プロパティにアクセスし、コンソールウィンドウに1〜10の偶数を表示できます。

foreach (int i in EvenNumbers)

     {

         Console.WriteLine(i);

     }

返される値がなくなったときに、イテレータ内で「yieldbreak」ステートメントを使用できます。「yieldbreak」ステートメントは、列挙を終了するために使用されます。

public IEnumerable GetData(IEnumerable items)

{

   if (null == items)

       yield break;

   foreach (T item in items)

       yield return item;

}

上記のコードリストを参照してください。「items」パラメータがnullかどうかを確認するためのチェック方法に注意してください。イテレータ内でパラメータとしてnullを指定してGetData()メソッドを呼び出すと、コントロールは値を返さずに呼び出し元に戻るだけです。

覚えておくべきポイント

yieldキーワードを使用するときは、次の点に注意する必要があります。

  • try-finallyブロック内に含めることはできますが、try-catchブロック内にyieldreturnステートメントを含めることはできません。
  • finishブロック内にyieldbreakステートメントを含めることはできません
  • yieldが使用されたメソッドの戻り値の型は、IEnumerable、IEnumerable、IEnumerator、またはIEnumeratorである必要があります。
  • 歩留まりが使用されているメソッドにrefまたはoutパラメーターを含めることはできません
  • 匿名メソッド内で「yieldreturn」または「yieldbreak」ステートメントを使用することはできません
  • 「unsafe」メソッド内で「yieldreturn」または「yieldbreak」ステートメントを使用することはできません。つまり、「unsafe」キーワードでマークされたメソッドは、安全でないコンテキストを示します。