次の方法で共有


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 の要素型です。

  • の型 Xdynamic の場合、 から 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 の中に、Tdynamic ではない固有の型 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 化される可能性があります。

代替

何もしません。

未解決の質問

この時点ではありません。