yield (C# リファレンス)
ステートメントで yield キーワードを使用した場合、メソッド、演算子、または get アクセサーが反復子であることを示します。 yield を使用して反復子を定義すると、カスタム コレクション型の IEnumerable および IEnumerator パターンを実装するときに明示的な余分なクラス (列挙の状態を保持するクラス。たとえば IEnumerator を参照) が不要になります。
yield ステートメントの 2 つの形式を次の例に示します。
yield return <expression>;
yield break;
解説
各要素を 1 つずつ返すには、yield return ステートメントを使用します。
foreach ステートメントまたは LINQ クエリを使用することにより、Iterator メソッドを処理します。 foreach ループの各イテレーションは、Iterator メソッドを呼び出します。 yield return ステートメントが Iterator メソッドに到達すると、expression が返され、コードの現在の位置が保持されます。 次回、Iterator 関数が呼び出されると、この位置から実行が再開されます。
yield break ステートメントを使用すると、反復を終了できます。
反復子の詳細については、「反復子 (C# および Visual Basic)」を参照してください。
Iterator メソッドと get アクセサー
反復子の宣言は、次の要件を満たす必要があります。
戻り値の型は、IEnumerable、IEnumerable、IEnumerator、または IEnumerator であることが必要です。
IEnumerable または IEnumerator を返す反復子の yield 型は object です。反復子が IEnumerable または IEnumerator を返す場合、yield return ステートメント内の式の型から、ジェネリック型パラメーターへの暗黙的な変換が存在する必要があります。
次の特性を持つメソッドに yield return ステートメントまたは yield break ステートメントを含めることはできません。
匿名メソッド。 詳細については、「匿名メソッド (C# プログラミング ガイド)」を参照してください。
unsafe ブロックを含むメソッド。 詳細については、「unsafe (C# リファレンス)」を参照してください。
例外処理
yield return ステートメントは、try-catch ブロックに配置することはできません。 yield return ステートメントは、try-finally ステートメントの try ブロックに配置できます。
yield break ステートメントは、try ブロックまたは catch ブロックには配置できますが、finally ブロックには配置できません。
foreach 本体 (Iterator メソッドの外部) で例外がスローされた場合、Iterator メソッドの finally ブロックが実行されます。
技術的な実装
次のコードは、iterator メソッドから IEnumerable<string> を返した後、要素を反復処理します。
IEnumerable<string> elements = MyIteratorMethod();
foreach (string element in elements)
{
…
}
MyIteratorMethod への呼び出しでは、メソッドの本体は実行されません。 この呼び出しでは、IEnumerable<string> が elements 変数に返されます。
foreach ループの反復処理では、elements について MoveNext メソッドが呼び出されます。 この呼び出しでは、次の yield return ステートメントに到達するまで、MyIteratorMethod の本体が実行されます。 yield return ステートメントによって返される式は、ループ本体による処理に対する element 変数の値だけでなく、IEnumerable<string> である要素の Current プロパティも決定します。
foreach ループの以降の各反復処理では、反復子本体の実行が中断した場所から続行し、yield return ステートメントに到達したときに再度停止します。 iterator メソッドまたは yield break ステートメントの最後に到達すると、foreach ループは完了します。
使用例
次の例では、for ループ内に yield return ステートメントが含まれます。 Process 内の foreach ステートメント本体の各反復処理では、Power Iterator 関数が呼び出されます。 Iterator 関数を呼び出すごとに、yield return ステートメントの次の実行に進みます。これは、for ループの次の反復処理で行われます。
Iterator メソッドの戻り値の型は IEnumerable であり、これは反復子インターフェイス型です。 Iterator メソッドが呼び出されると、数値の累乗を含む列挙可能なオブジェクトが返されます。
public class PowersOf2
{
static void Main()
{
// Display powers of 2 up to the exponent of 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
{
int result = 1;
for (int i = 0; i < exponent; i++)
{
result = result * number;
yield return result;
}
}
// Output: 2 4 8 16 32 64 128 256
}
次の例は、反復子である get アクセサーを示しています。 この例では、各 yield return ステートメントがユーザー定義クラスのインスタンスを返します。
public static class GalaxyClass
{
public static void ShowGalaxies()
{
var theGalaxies = new Galaxies();
foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy)
{
Debug.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString());
}
}
public class Galaxies
{
public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy
{
get
{
yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
}
}
}
public class Galaxy
{
public String Name { get; set; }
public int MegaLightYears { get; set; }
}
}
C# 言語仕様
詳細については、「C# 言語仕様」を参照してください。言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。