共用方式為


GetEnumerator 擴充功能支援 foreach 循環。

注意

本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。

功能規格與已完成實作之間可能有一些差異。 這些差異被記錄在相關的 語言設計會議(LDM)中。

您可以在 規格的文章中,詳細了解在 C# 語言標準中採納功能規格的流程

冠軍問題:https://github.com/dotnet/csharplang/issues/3194

總結

允許 foreach 循環辨識滿足 foreach 模式的擴充方法 GetEnumerator,並在一般會導致錯誤的情況下對表達式進行迴圈執行。

動機

這將使 foreach 與 C# 中其他功能的實作方式一致,包括非同步和以模式為基礎的解構。

詳細設計

規格變更相對簡單。 我們將 The foreach statement§13.9.5 一節修改為此文字:

foreach 語句的編譯時間處理會先決定表達式的 集合類型列舉值類型項目類型。 此判斷如下進行:

  • 如果 X 的類型 是陣列類型,則存在一個從 XIEnumerable 介面的隱式參考轉換(因為 System.Array 實作這個介面)。 集合類型IEnumerable 介面,列舉值類型IEnumerator 介面,而 項目類型 是數位類型 X的項目類型。

  • 如果 X 的類型是 dynamic,則會從 表示式 隱含轉換成 IEnumerable 介面(§10.2.10)。 集合類型IEnumerable 介面,而 列舉值類型IEnumerator 介面。 如果將 var 識別元指定為 local_variable_type,則 項目類型dynamic,否則為 object

  • 否則,請判斷類型 X 是否有適當的 GetEnumerator 方法:

    • 使用標識碼 X 且沒有類型自變數,對類型 GetEnumerator 執行成員查閱。 如果搜尋成員未能產生匹配結果、產生不明確的匹配或產生非方法群組的匹配,應檢查可列舉的介面,如下所述。 如果成員查找產生除方法群組外的任何結果,或沒有找到匹配,建議發出警告。
    • 使用產生的方法群組和空的自變數清單來執行多載解析。 如果多載解析沒有產生任何適用的方法、產生模棱兩可的方法,或產生單一最佳方法,但該方法為靜態或不公用,請檢查可列舉的介面,如下所示。 如果多載解析不是產生明確的公用實例方法或無可應用的方法,建議發出警告。
    • 如果 E 方法的傳回型別 GetEnumerator 不是類別、結構或介面類型,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 成員查找會在具有識別符 E 且沒有類型引數的 Current 上執行。 如果成員查詢沒有產生任何匹配的對象,則會產生錯誤;或者如果結果不是允許讀取的公用實例屬性,則同樣會產生錯誤,且不再進行任何其他步驟。
    • 成員查找會在具有識別符 E 且沒有類型引數的 MoveNext 上執行。 如果成員查閱不會產生任何相符專案,則結果為錯誤,或結果為方法群組以外的任何專案,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 多載解析是在具有空自變數清單的方法群組上執行。 如果多載解析沒有產生任何適用的方法、造成模棱兩可,或產生單一最佳方法,但該方法為靜態或非公用方法,或其傳回類型未 bool,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 集合類型X列舉值類型E,而 項目類型Current 屬性的類型。
  • 否則,請檢查可列舉的介面:

    • 如果在從 Ti 隱含轉換成 X的所有類型 IEnumerable<Ti> 之間,有一個唯一的類型 T,使得 T 不是 dynamic,而所有其他 Ti 都有從 IEnumerable<T>IEnumerable<Ti>的隱含轉換,則 集合類型 為 介面 IEnumerable<T>列舉值類型 是介面 IEnumerator<T>,而 項目類型T
    • 否則,如果有多個這類類型 T,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 否則,如果從 隱含轉換成 介面,則 集合類型 為這個介面,則 列舉值類型 為介面 ,而 項目類型
  • 否則,請判斷類型 『X』 是否具有適當的 GetEnumerator 擴充方法:

    • 使用標識碼 X,對類型 GetEnumerator 執行擴充方法查閱。 如果成員查閱未產生匹配項,或者產生模棱兩可的結果,或者產生與方法群組不符的匹配項,將會發生錯誤,不會進行任何進一步的步驟。 如果成員查閱產生方法群組以外的任何專案,或沒有任何相符專案,建議發出警告。
    • 使用產生的方法群組,並以X類型的單一自變數執行多載解析。 如果多載解析沒有產生適用的方法、導致模稜兩可,或是找到了單一最佳方法但該方法無法存取,則會產生錯誤並不會進行任何進一步的步驟。
      • 如果 X 是結構類型,而且 ref 種類 in,則此解析允許 ref 傳遞第一個自變數。
    • 如果 E 方法的傳回型別 GetEnumerator 不是類別、結構或介面類型,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 成員查找會在具有識別符 E 且沒有類型引數的 Current 上執行。 如果成員查詢沒有產生任何匹配的對象,則會產生錯誤;或者如果結果不是允許讀取的公用實例屬性,則同樣會產生錯誤,且不再進行任何其他步驟。
    • 成員查找會在具有識別符 E 且沒有類型引數的 MoveNext 上執行。 如果成員查閱不會產生任何相符專案,則結果為錯誤,或結果為方法群組以外的任何專案,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 多載解析是在具有空自變數清單的方法群組上執行。 如果多載解析沒有產生任何適用的方法、造成模棱兩可,或產生單一最佳方法,但該方法為靜態或非公用方法,或其傳回類型未 bool,則會產生錯誤,而且不會採取任何進一步的步驟。
    • 集合類型X列舉值類型E,而 項目類型Current 屬性的類型。
  • 否則,會產生錯誤,而且不會採取任何進一步的步驟。

針對 await foreach,規則會同樣修改。 該規格所需的唯一變更是從描述中移除 Extension methods do not contribute. 行,因為該規格的其餘部分是以上述規則為基礎,並使用不同的名稱取代模式方法。

缺點

每個變更都會為語言增加額外的複雜度,這可能會讓原本不適用於 foreachforeach的事物變得適用,例如 Range

替代方案

無所事事。

未解決的問題

此刻沒有。