foreach
ループのための拡張機能 GetEnumerator
のサポート。
手記
この記事は機能仕様です。 仕様は、機能の設計ドキュメントとして機能します。 これには、提案された仕様の変更と、機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が最終決定され、現在の ECMA 仕様に組み込まれるまで公開されます。
機能の仕様と完成した実装の間には、いくつかの違いがある可能性があります。 これらの違いは、関連する 言語設計会議 (LDM) ノートでキャプチャされます。
機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。
概要
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
からIEnumerable<Ti>
への暗黙的な変換があるすべての型Ti
の中に、T
がdynamic
ではなく、他のすべてのTi
に対してIEnumerable<T>
からIEnumerable<Ti>
への暗黙的な変換が存在するように一意の型T
がある場合、コレクション型 はインターフェイス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
されていない場合、エラーが生成され、それ以上の手順は実行されません。コレクション型が され、 が 列挙子の型 され、 は 要素の型 プロパティの型です。 それ以外の場合は、エラーが生成され、それ以上の手順は実行されません。
await foreach
の場合、規則も同様に変更されます。 そのスペックに必要な唯一の変更は、説明から Extension methods do not contribute.
行を削除することです。その仕様の残りの部分は、パターン メソッドに置き換わる名前が異なる上記の規則に基づいているためです。
欠点
変更が加えられるたびに言語はさらに複雑になり、これにより、foreach
化されるように設計されていないものが Range
のように foreach
化される可能性があります。
選択肢
何もしない。
未解決の質問
この時点ではなし。
C# feature specifications