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 vonX
zurIEnumerable
-Schnittstelle (daSystem.Array
diese Schnittstelle implementiert). Der -Sammlungstyp ist dieIEnumerable
-Schnittstelle, der -Enumerationstyp ist dieIEnumerator
-Schnittstelle, und der -Elementtyp ist der Elementtyp des Array-TypsX
.Wenn der Typ
X
des Ausdrucks ist,dynamic
gibt es eine implizite Konvertierung von Ausdruck in dieIEnumerable
Schnittstelle (§10.2.10). Der Sammlungstyp ist dieIEnumerable
-Schnittstelle und der Enumerationstyp ist dieIEnumerator
-Schnittstelle. Wenn dervar
-Bezeichner als local_variable_type angegeben wird, dann ist der Elementtypdynamic
, andernfalls ist esobject
.Ermitteln Sie andernfalls, ob der Typ
X
über eine geeigneteGetEnumerator
-Methode verfügt:
- Führen Sie die Membersuche für den Typ
X
mit dem BezeichnerGetEnumerator
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
derGetEnumerator
-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 BezeichnerCurrent
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 BezeichnerMoveNext
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 istE
, und der Elementtyp ist der Typ derCurrent
-Eigenschaft.Suchen Sie andernfalls nach einer aufzählbaren Schnittstelle:
- Wenn es unter allen Typen
Ti
, für die eine implizite Konvertierung vonX
zuIEnumerable<Ti>
möglich ist, einen eindeutigen TypT
gibt, sodassT
nicht identisch mitdynamic
ist und für alle anderenTi
eine implizite Konvertierung vonIEnumerable<T>
zuIEnumerable<Ti>
möglich ist, dann ist der -Sammlungstyp die SchnittstelleIEnumerable<T>
, der -Enumerationstyp ist die SchnittstelleIEnumerator<T>
und der -Elementtyp istT
.- 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
zurSystem.Collections.IEnumerable
-Schnittstelle gibt, dann ist der -Sammlungstyp diese Schnittstelle, der -Enumerator-Typ die SchnittstelleSystem.Collections.IEnumerator
, und der -Elementtyp istobject
.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 BezeichnerGetEnumerator
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-Kategoriein
ist.- Wenn der Rückgabetyp
E
derGetEnumerator
-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 BezeichnerCurrent
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 BezeichnerMoveNext
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 istE
, und der Elementtyp ist der Typ derCurrent
-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.
C# feature specifications