GetEnumerator
ループのための拡張機能 foreach
のサポート。
メモ
この記事は機能仕様についてです。 仕様は、機能の設計ドキュメントとして使用できます。 これには、提案された仕様の変更および機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が決定され、現在の ECMA 仕様に組み込まれるまで公開されます。
機能の仕様と行われた実装では、いくつかの違いがあることがあります。 これらの違いは、関連する言語設計ミーティング (LDM) メモに取り上げられています。
機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。
チャンピオンの課題: https://github.com/dotnet/csharplang/issues/3194
まとめ
foreach
ループが、foreach パターンを満たす拡張メソッド GetEnumerator
メソッドを認識できるようにし、そうでなければエラーになる場合に式をループします。
目的
これにより、非同期およびパターンベースの分解など、C# の他の機能の実装方法に foreach
がインラインで対応できるようになります。
詳細な設計
仕様の変更は比較的シンプルです。 The foreach statement
§13.9.5 セクションをこのテキストに変更します。
foreach ステートメントのコンパイル時の処理では、まず、式のコレクション型、列挙子型、要素型を決定します。 この決定は次のように進みます。
式の型
X
が配列型の場合、X
からIEnumerable
インターフェイスへの暗黙的な参照変換があります (System.Array
はこのインターフェイスを実装するため)。 コレクション型はIEnumerable
インターフェイス、列挙子型はIEnumerator
インターフェイス、要素型 は配列型X
の要素型です。式の型
X
がdynamic
の場合、式 からIEnumerable
インターフェイス (§10.2.10) への暗黙的な変換があります。 コレクション型はIEnumerable
インターフェイスであり、列挙子型 はIEnumerator
インターフェイスです。var
識別子が local_variable_type として指定されている場合、要素型はdynamic
です。それ以外の場合はobject
になります。それ以外の場合は、型
X
に適切なGetEnumerator
メソッドがあるかどうかを判断します。
- 識別子
GetEnumerator
を持ち、型引数を持たない型X
に対してメンバー参照を実行します。 メンバー参照で一致が生成されない場合、またはあいまいさが生成される場合、あるいはメソッド グループではない一致が生成される場合は、次に説明するように列挙可能なインターフェイスを確認します。 メンバー参照でメソッド グループ以外の何かを生成する場合、または一致するものがない場合は、警告を発行することをお勧めします。- 最終的なメソッド グループと空の引数リストを使用して、オーバーロードの解決を実行します。 オーバーロードの解決によって該当するメソッドが存在しない場合、あいまいになる場合、または単一の最適なメソッドになるが、そのメソッドが静的であるかパブリックでない場合は、次に説明するように列挙可能なインターフェイスを確認します。 オーバーロードの解決で明確なパブリック インスタンス メソッド以外の何かを生成する場合、または該当するメソッドが生成されない場合は、警告を発行することをお勧めします。
GetEnumerator
メソッドの戻り値の型E
がクラス、構造体、またはインターフェイス型でない場合は、エラーが生成され、それ以上の手順は実行されません。- 識別子
Current
を持ち、型引数を持たないE
に対してメンバー参照を実行します。 メンバー参照で一致が生成されない場合、結果がエラーである場合、または読み取りを許可するパブリック インスタンス プロパティ以外の結果である場合は、エラーが生成され、それ以上の手順は実行されません。- 識別子
MoveNext
を持ち、型引数を持たないE
に対してメンバー参照を実行します。 メンバー参照で一致が生成されない場合、結果がエラーである場合、または結果がメソッド グループを除くものである場合、エラーが生成され、それ以上の手順は実行されません。- オーバーロードの解決は、空の引数リストを使用してメソッド グループに対して実行されます。 オーバーロードの解決の結果、適用可能なメソッドが得られない場合、あいまいさが生じる場合、または 1 つの最適なメソッドになるものの、そのメソッドが静的であるかパブリックでない場合、あるいはその戻り値の型が
bool
ではない場合、エラーが生成され、それ以上の手順は実行されません。- コレクション型は
X
、列挙型はE
、要素型 はCurrent
プロパティの型です。それ以外の場合は、列挙可能なインターフェイスを確認します。
X
からIEnumerable<Ti>
への暗黙的な変換が存在するすべての型Ti
の中に、T
がdynamic
ではない固有の型T
があり、他のすべてのTi
についてIEnumerable<T>
からIEnumerable<Ti>
への暗黙的な変換がある場合、コレクション型はインターフェイスIEnumerable<T>
、列挙子型はインターフェイスIEnumerator<T>
、要素型はT
です。- それ以外では、このような型
T
が複数存在する場合 、エラーが生成され、それ以上の手順は実行されません。- それ以外の場合、
X
からSystem.Collections.IEnumerable
インターフェイスへの暗黙的な変換がある場合、コレクション型はこのインターフェイス、列挙子型はインターフェイスSystem.Collections.IEnumerator
、要素型 はobject
です。それ以外の場合は、型 'X' に適切な
GetEnumerator
拡張メソッドがあるかどうかを確認します。
- 識別子
GetEnumerator
を持つ型X
に対して拡張メソッド検索を実行します。 メンバー検索で一致が生成されない場合、またはあいまいさが生成された場合、あるいはメソッド グループではない一致が生成された場合は、エラーが生成され、それ以上の手順は実行されません。 メンバー参照でメソッド グループ以外の何かを生成する場合、または一致するものがない場合は、警告を発行することをお勧めします。- 最終的なメソッド グループと、
X
型の 1 つの引数を使用してオーバーロードの解決を実行します。 オーバーロードの解決で該当するメソッドが生成されない場合、あいまいになる場合、または 1 つの最適なメソッドになるが、そのメソッドにアクセスできない場合は、エラーが生成され、それ以上の手順は実行されません。
- この解決により、
X
が構造体型で ref の種類がin
の場合、最初の引数を ref で渡すことができます。GetEnumerator
メソッドの戻り値の型E
がクラス、構造体、またはインターフェイス型でない場合は、エラーが生成され、それ以上の手順は実行されません。- 識別子
Current
を持ち、型引数を持たないE
に対してメンバー参照を実行します。 メンバー参照で一致が生成されない場合、結果がエラーである場合、または読み取りを許可するパブリック インスタンス プロパティ以外の結果である場合は、エラーが生成され、それ以上の手順は実行されません。- 識別子
MoveNext
を持ち、型引数を持たないE
に対してメンバー参照を実行します。 メンバー参照で一致が生成されない場合、結果がエラーである場合、または結果がメソッド グループを除くものである場合、エラーが生成され、それ以上の手順は実行されません。- オーバーロードの解決は、空の引数リストを使用してメソッド グループに対して実行されます。 オーバーロードの解決の結果、適用可能なメソッドが得られない場合、あいまいさが生じる場合、または 1 つの最適なメソッドになるものの、そのメソッドが静的であるかパブリックでない場合、あるいはその戻り値の型が
bool
ではない場合、エラーが生成され、それ以上の手順は実行されません。- コレクション型は
X
、列挙型はE
、要素型 はCurrent
プロパティの型です。それ以外の場合はエラーが生成され、それ以上の手順は実行されません。
await foreach
の場合、ルールも同様に変更されます。 その仕様に必要な唯一の変更は、説明から Extension methods do not contribute.
行を削除することです。その仕様の残りの部分は、パターン メソッドに置き換わる名前が異なる上記のルールに基づいているためです。
デメリット
変更が加えられるたびに言語はさらに複雑になり、これにより、foreach
化されるように設計されていないものが Range
のように foreach
化される可能性があります。
代替
何もしません。
未解決の質問
この時点ではありません。
C# feature specifications