Freigeben über


Unterstützung für die Erweiterung GetEnumerator in foreach-Schleifen.

Hinweis

Dieser Artikel ist eine Feature-Spezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.

Es kann einige Abweichungen zwischen der Feature-Spezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den entsprechenden Hinweisen zum Language Design Meeting (LDM) erfasst.

Weitere Informationen zum Prozess für die Aufnahme von Funktions-Speclets in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.

Champion-Problem: https://github.com/dotnet/csharplang/issues/3194

Zusammenfassung

Erlauben, dass foreach-Schleifen eine GetEnumerator-Methode erkennen, die ansonsten dem foreach-Muster entspricht, und über den Ausdruck iterieren, wenn ansonsten ein Fehler auftreten würde.

Motivation

Dies bringt foreach in Einklang mit der Implementierung anderer Features in C#, einschließlich async und musterbasierter Dekonstruktion.

Detailliertes Design

Die Spezifikationsänderung ist relativ einfach. Wir ändern The foreach statement§13.9.5-Abschnitt in diesen Text:

Die Kompilierungszeitverarbeitung einer foreach-Anweisung bestimmt zuerst den Auflistungstyp, Enumerationstyp und Elementtyp des Ausdrucks. Diese Feststellung erfolgt wie folgt:

  • Wenn der Typ X des Ausdrucks ein Arraytyp ist, gibt es eine implizite Verweiskonvertierung von X zur IEnumerable-Schnittstelle (da System.Array diese Schnittstelle implementiert). Der -Sammlungstyp ist die IEnumerable-Schnittstelle, der -Enumerationstyp ist die IEnumerator-Schnittstelle, und der -Elementtyp ist der Elementtyp des Array-Typs X.

  • Wenn der Typ X des Ausdrucks ist,dynamic gibt es eine implizite Konvertierung von Ausdruck in die IEnumerable Schnittstelle (§10.2.10). Der Sammlungstyp ist die IEnumerable-Schnittstelle und der Enumerationstyp ist die IEnumerator-Schnittstelle. Wenn der var-Bezeichner als local_variable_type angegeben wird, dann ist der Elementtypdynamic, andernfalls ist es object.

  • Ermitteln Sie andernfalls, ob der Typ X über eine geeignete GetEnumerator-Methode verfügt:

    • Führen Sie die Membersuche für den Typ X mit dem Bezeichner GetEnumerator und ohne Typargumente durch. Wenn die Membersuche keine Übereinstimmung liefert oder eine Mehrdeutigkeit vorliegt oder eine Übereinstimmung liefert, die keine Methodengruppe ist, suchen Sie nach einer aufzählbaren Schnittstelle, wie unten beschrieben. Es wird empfohlen, eine Warnung auszugeben, wenn die Mitgliedersuche etwas anderes als eine Methodengruppe oder keine Übereinstimmung liefert.
    • Führen Sie die Überladungsauflösung mithilfe der resultierenden Methodengruppe und einer leeren Argumentliste aus. Wenn die Überladungsauflösung zu keiner anwendbaren Methode führt, eine Mehrdeutigkeit verursacht oder lediglich die beste Methode ergibt, die jedoch entweder statisch oder nicht öffentlich ist, prüfen Sie auf eine aufzählbare Schnittstelle, wie unten beschrieben. Es wird empfohlen, dass eine Warnung ausgegeben wird, wenn die Überladungsauflösung nichts anderes als eine eindeutige öffentliche Instanzmethode oder keine anwendbaren Methoden erzeugt.
    • Wenn der Rückgabetyp E der GetEnumerator-Methode keine Klasse, Struktur oder kein Schnittstellentyp ist, wird ein Fehler erzeugt und es werden keine weiteren Schritte ausgeführt.
    • Membersuche wird bei E mit dem Bezeichner Current und ohne Typargumente durchgeführt. Wenn die Membersuche keine Übereinstimmung ergibt, das Ergebnis ein Fehler ist oder es sich bei dem Ergebnis nicht um eine öffentliche Instanz-Eigenschaft handelt, die das Lesen zulässt, wird ein Fehler erzeugt, und es werden keine weiteren Schritte unternommen.
    • Membersuche wird bei E mit dem Bezeichner MoveNext und ohne Typargumente durchgeführt. Wenn die Suche nach einem Mitglied keine Übereinstimmung ergibt oder das Ergebnis etwas anderes als eine Methodengruppe ist, wird ein Fehler erzeugt; und es werden keine weiteren Schritte unternommen.
    • Die Auflösung von Überladungen wird für die Methodengruppe mit einer leeren Argumentliste durchgeführt. Führt die Überladungsauflösung zu keiner anwendbaren Methode, führt zu einer Mehrdeutigkeit oder führt zu einer einzigen besten Methode, aber diese Methode ist entweder statisch oder nicht öffentlich, oder der Rückgabetyp ist nicht bool, wird ein Fehler erzeugt, und es werden keine weiteren Schritte ausgeführt.
    • Der Sammlungstyp ist X, der Aufzählungstyp ist E, und der Elementtyp ist der Typ der Current-Eigenschaft.
  • Suchen Sie andernfalls nach einer aufzählbaren Schnittstelle:

    • Wenn es unter allen Typen Ti, für die eine implizite Konvertierung von X zu IEnumerable<Ti> möglich ist, einen eindeutigen Typ T gibt, sodass T nicht identisch mit dynamic ist und für alle anderen Ti eine implizite Konvertierung von IEnumerable<T> zu IEnumerable<Ti> möglich ist, dann ist der -Sammlungstyp die Schnittstelle IEnumerable<T>, der -Enumerationstyp ist die Schnittstelle IEnumerator<T> und der -Elementtyp ist T.
    • Andernfalls wird bei mehr als einem solchen Typ T ein Fehler erzeugt und es werden keine weiteren Schritte ausgeführt.
    • Andernfalls, wenn es eine implizite Konvertierung von X zur System.Collections.IEnumerable-Schnittstelle gibt, dann ist der -Sammlungstyp diese Schnittstelle, der -Enumerator-Typ die Schnittstelle System.Collections.IEnumerator, und der -Elementtyp ist object.
  • Ermitteln Sie andernfalls, ob der Typ „X“ über eine geeignete GetEnumerator-Erweiterungsmethode verfügt.

    • Führen Sie die Erweiterungsmethode für den Typ X mit Bezeichner GetEnumerator aus. Wenn die Membersuche keine Übereinstimmung findet, eine Mehrdeutigkeit ergibt oder eine Übereinstimmung liefert, bei der es sich nicht um eine Methodengruppe handelt, tritt ein Fehler auf, und es werden keine weiteren Schritte ausgeführt. Es wird empfohlen, eine Warnung auszugeben, wenn die Membersuche etwas anderes als eine Methodengruppe oder keine Übereinstimmung liefert.
    • Führen Sie die Überladungsauflösung mit der resultierenden Methodengruppe und einem einzelnen Argument vom Typ X aus. Wenn die Überladungsauflösung keine anwendbaren Methoden erzeugt, zu einer Mehrdeutigkeit führt oder eine einzige beste Methode ergibt, diese Methode jedoch nicht zugänglich ist, wird ein Fehler erzeugt, und es werden keine weiteren Schritte ausgeführt.
      • Mit dieser Resolution kann das erste Argument als Referenz übergeben werden, wenn X ein Strukturtyp ist und die Ref-Kategorie in ist.
    • Wenn der Rückgabetyp E der GetEnumerator-Methode keine Klasse, Struktur oder kein Schnittstellentyp ist, wird ein Fehler erzeugt und es werden keine weiteren Schritte ausgeführt.
    • Membersuche wird bei E mit dem Bezeichner Current und ohne Typargumente durchgeführt. Wenn die Membersuche keine Übereinstimmung ergibt, das Ergebnis ein Fehler ist oder es sich bei dem Ergebnis nicht um eine öffentliche Instanz-Eigenschaft handelt, die das Lesen zulässt, wird ein Fehler erzeugt, und es werden keine weiteren Schritte unternommen.
    • Membersuche wird bei E mit dem Bezeichner MoveNext und ohne Typargumente durchgeführt. Wenn die Suche nach einem Mitglied keine Übereinstimmung ergibt oder das Ergebnis etwas anderes als eine Methodengruppe ist, wird ein Fehler erzeugt; und es werden keine weiteren Schritte unternommen.
    • Die Auflösung von Überladungen wird für die Methodengruppe mit einer leeren Argumentliste durchgeführt. Führt die Überladungsauflösung zu keiner anwendbaren Methode, führt zu einer Mehrdeutigkeit oder führt zu einer einzigen besten Methode, aber diese Methode ist entweder statisch oder nicht öffentlich, oder der Rückgabetyp ist nicht bool, wird ein Fehler erzeugt, und es werden keine weiteren Schritte ausgeführt.
    • Der Sammlungstyp ist X, der Aufzählungstyp ist E, und der Elementtyp ist der Typ der Current-Eigenschaft.
  • Andernfalls wird ein Fehler erzeugt und es werden keine weiteren Schritte ausgeführt.

Für await foreach werden die Regeln entsprechend geändert. Die einzige Änderung, die für diese Spezifikation erforderlich ist, ist das Entfernen der Zeile Extension methods do not contribute. aus der Beschreibung, da der Rest dieser Spezifikation auf den oben genannten Regeln basiert, mit unterschiedlichen Namen anstelle der Mustermethoden.

Nachteile

Jede Änderung fügt der Sprache zusätzliche Komplexität hinzu, und dies könnte potenziell Dinge ermöglichen, die nicht dafür ausgelegt waren, foreach zu foreach, wie z. B. Range.

Alternativen

Nichts tun.

Ungelöste Fragen

Zu diesem Zeitpunkt nicht.