22 反復子
22.1 反復子ブロック
反復子ブロックは、順序付けられた値のシーケンスを生成するステートメントのブロックです。イテレータ ブロックは、1 つ以上の yield ステートメントによって通常のステートメント ブロックと区別されます。
l yield return ステートメントは、反復の次の値を生成します。
l yield Break ステートメントは、反復が完了したことを示します。対応する関数メンバーの戻り値の型が列挙子のいずれか 1 つである場合、反復子ブロックはメソッド本体、演算子本体、またはアクセサー本体として使用できます。
反復子ブロックは、C# 構文における固有の要素ではありません。これらはいくつかの方法で制限されており、主に関数メンバー宣言のセマンティクスに影響しますが、構文的には単なるステートメントのブロックです。
関数メンバーがイテレータ ブロックを使用して実装されている場合、仮パラメータ リストに ref パラメータまたは out パラメータを指定すると、コンパイル時エラーが発生します。
反復子ブロック内に出現する return ステートメントはコンパイル時エラーを引き起こします (ただし、yield return ステートメントは許可されます)。
安全でないコンテキスト (§18.1) を反復子ブロックに含めると、コンパイル時エラーが発生します。イテレータ宣言が安全でないコンテキストに埋め込まれている場合でも、イテレータ ブロックは常に安全なコンテキストとして定義されます。
l イテレータ ブロックの yield 型は、通常、IEnumerator または IEnumerable オブジェクトを返す関数メンバーを実装するために使用されます。
l イテレータ ブロックの yield 型は、通常、IEnumerator
構造体のインスタンスメンバーのイテレータブロックでは、これを変数として表現します。変数の型は、この方法で使用できる構造体の型です。この変数は、メンバーが呼び出されたときの対応する構造体のコピーを表します。構造体インスタンス メンバーの反復子ブロック内では、 this 変数は構造体型の値パラメーターであるかのように動作します。
22.2 列挙オブジェクト
列挙子インターフェイス型を返す関数メンバーが反復子ブロックを使用して実装されている場合、関数メンバーを呼び出しても、反復子ブロック内のコードはすぐには実行されません。代わりに、列挙子オブジェクトが作成されて返されます。このオブジェクトは、反復子ブロックで指定されたコードをカプセル化します。列挙子オブジェクトの MoveNext メソッドが呼び出されると、反復子ブロック内のコードが実行されます。列挙子オブジェクトには次の特性があります。
l IEnumerator と IEnumerator
l System.IDisposable を実装します。
l 引数の値 (存在する場合) のコピーで初期化され、インスタンス値が関数メンバーに渡されます。
l 実行前、実行中、中断中、実行後の 4 つの潜在的な状態があり、前の状態の前に初期化されます。
列挙子オブジェクトは通常、コンパイラによって生成された列挙子クラスのインスタンスであり、反復子ステートメント ブロックにコードをカプセル化し、列挙子インターフェイスを実装しますが、他の実装方法も可能です。列挙子クラスがコンパイラによって生成される場合、そのクラスは埋め込まれ、関数メンバーを含むクラス内でプライベートなアクセスが可能になり、クラスにはコンパイラで使用するために予約された名前が付けられます (§2.4.2)。
Enumerator オブジェクトは、ここで指定されているものよりも多くのインターフェイスを実装できます。次のセクションでは、列挙オブジェクトによって提供される IEnumerable および IEnumerable
列挙子オブジェクトは IEnumerator.Reset メソッドをサポートしていないことに注意してください。このメソッドを呼び出すと、System.NotSupportedException 例外がスローされます。
列挙子オブジェクトの MoveNext メソッドは、反復子ブロックのコードをカプセル化します。 MoveNext メソッドを呼び出すと、イテレータ内のコードが実行され、列挙オブジェクトの Current プロパティが適切な値に設定されます。 MoveNext メソッドによって実行される正確なアクションは、MoveNext メソッドが呼び出されたときの列挙子オブジェクトの状態によって異なります。
l 列挙子オブジェクトの状態が before の場合、MoveNext
n を呼び出すと状態が実行中に変更されます。
n は、イテレータ ブロック (これを含む) のパラメータを、列挙子オブジェクトの初期化時に保存された実際のパラメータ値とインスタンス値に初期化します。
n (以下で説明するように) 実行が中断されるまで、反復子ブロックを最初から実行します。
l 列挙子オブジェクトのステータスが実行中の場合、MoveNext の呼び出し結果は不定です。
l 列挙子オブジェクトのステータスが一時停止の場合、MoveNext
n を呼び出すとステータスが実行中に変更されます。
l すべてのローカル変数とパラメータ (これを含む) の値を、反復子が最後に一時停止された (中断された) ときの実行状態の値に復元します。これらの変数によって参照されるオブジェクトの内容は、前回の MoveNext の呼び出し以降に変更されている可能性があることに注意してください。
n 反復子ブロックの実行は、実行の中断を引き起こした yield return ステートメントの後に再開され、この状態は実行が中断されるまで継続します (後述)。
l 列挙子オブジェクトの状態が after の場合、MoveNext を呼び出すと false が返されます。
MoveNext がイテレータ ブロックを実行する場合、実行を中断する方法は 4 つあります。yield return ステートメントを使用する場合、yield Break ステートメントを使用する場合、イテレータ ブロックの終了点に到達した場合、および例外がスローされてイテレータに伝播された場合です。ブロックの外側。
l yield return ステートメント (§22.4) が出現すると、次のことが起こります。
n ステートメントで指定された式が評価され、暗黙的に yield 型に変換され、列挙オブジェクトの Current プロパティに割り当てられます。
n イテレータ本体の実行は一時停止されます。すべてのローカル変数とパラメータ (これを含む) の値は、yield return ステートメントの位置と同様に保存されます。 yield return ステートメントが 1 つ以上の try ブロック内にある場合、この時点では関連する Final ブロックは実行されません。
n 列挙子オブジェクトのステータスが一時停止に変更されます。
n MoveNext メソッドは呼び出し元に true を返し、反復子が次の値に正常に進んだことを示します。
l yield Break ステートメントが見つかると、次のことが起こります。
n yield Break ステートメントが 1 つ以上の try ブロック内にある場合、それに関連付けられたfinally ステートメントが実行されます。
n 列挙子オブジェクトの状態が after に変更されます。
n MoveNext メソッドは呼び出し元に false を返し、反復が完了したことを示します。
l イテレータブロックの終点に到達すると、次のことが起こります。
n 列挙子オブジェクトの状態が after に変更されます。
n MoveNext メソッドは呼び出し元に false を返し、反復が完了したことを示します。
l 例外がスローされ、反復子ブロックの外に伝播されると、次のことが起こります。
n 例外の伝播により、適切なfinallyブロックがイテレータブロック内で実行されます。
n 列挙子オブジェクトの状態が after に変更されます。
n MoveNext メソッドの呼び出し元では、例外の伝播が続行されます。
22.2.2 Current プロパティ
列挙子オブジェクトの Current プロパティは、反復子ブロックの yield return ステートメントの影響を受けます。
列挙子オブジェクトが一時停止状態にある場合、Current の値は、MoveNext が最後に呼び出されたときに設定された値です。列挙子オブジェクトが before、running、または after 状態にある場合、Current にアクセスした結果は不定です。
非オブジェクト型の yield 型反復子ブロックの場合、列挙子オブジェクトの IEnumerable 実装を通じて Current にアクセスすることによって取得される実装は、列挙子オブジェクトの IEnumerator
22.2.3 破棄方法
Dispose メソッドは、列挙子オブジェクトの状態を after に設定することで反復結果をクリーンアップします。
l 列挙子オブジェクトの状態が before の場合、Dispose を呼び出すと状態が after に変更されます。
l 列挙子オブジェクトのステータスが実行中の場合、Dispose を呼び出した結果は指定されたものになります。
l 列挙子オブジェクトのステータスが一時停止の場合、Dispose を呼び出すと、そのステータスが実行中に変更されます。
n 最後に実行された yield return ステートメントが yield Break ステートメントであるかのように、finally ブロックを実行します。ここで例外がスローされ、イテレータ本体の外に伝播された場合、列挙子オブジェクトの状態は after に設定され、例外は Dispose メソッドの呼び出し元に伝播されます。
n ステータスを after に変更します。
l 列挙子オブジェクトのステータスが after の場合、Dispose を呼び出しても効果はありません。
l IEnumerable および IEnumerable
l 引数の値 (存在する場合) のコピーで初期化され、インスタンス値を関数メンバーに渡します。
列挙可能オブジェクトは通常、反復子ブロックのコードをカプセル化し、列挙可能インターフェイスを実装する、コンパイラによって生成された列挙可能クラスのインスタンスですが、他の実装方法も可能です。列挙可能なクラスがコンパイラによって生成される場合、そのクラスは関数メンバーを含むクラスに埋め込まれ、プライベート アクセシビリティとコンパイラが使用するために予約された名前を持ちます (§2.4.2)。
Eumerable オブジェクトは、ここで説明したものよりも多くのインターフェイスを実装できます。特に、列挙可能オブジェクトは IEnumerator および IEnumerator
列挙オブジェクトは実際のパラメータ値で初期化されます。一方、列挙オブジェクトの関数は §22.2 で説明したとおりです。
(続きます)