次の方法で共有


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

  • の型 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 から IEnumerable<Ti>への暗黙的な変換があるすべての型 Ti の中に、Tdynamic ではなく、他のすべての 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 化される可能性があります。

選択肢

何もしない。

未解決の質問

この時点ではなし。