Tillägg av stöd för GetEnumerator
i foreach
-loopar.
Not
Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.
Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader samlas in i de relevanta LDM-anteckningar (Language Design Meeting).
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Champion-fråga: https://github.com/dotnet/csharplang/issues/3194
Sammanfattning
Tillåt foreach
-loopar att identifiera en tilläggsmetod GetEnumerator
metod som annars uppfyller foreach-mönstret och loopa över uttrycket när det annars skulle vara ett fel.
Motivation
Detta kommer att göra foreach
i linje med hur andra funktioner i C# implementeras, inklusive asynkrona och mönsterbaserade dekonstruktioner.
Detaljerad design
Specifikationsändringen är relativt enkel. Vi ändrar The foreach statement
§13.9.5 avsnitt till denna text:
Kompileringstidsbearbetningen av en foreach-instruktion avgör först samlingstyp, uppräkningstyp och elementtyp för uttrycket. Den här bedömningen fortsätter på följande sätt:
Om typen
X
av uttryck är en matristyp finns det en implicit referenskonvertering frånX
tillIEnumerable
-gränssnittet (eftersomSystem.Array
implementerar det här gränssnittet). Den samlingstypen ärIEnumerable
-gränssnittet, uppräkningstyp ärIEnumerator
-gränssnittet och -elementtypen är elementtypen för matristypenX
.Om typen
X
av uttryck ärdynamic
sker en implicit konvertering från uttryck till gränssnittetIEnumerable
(§10.2.10). Den samlingstypen ärIEnumerable
-gränssnittet och uppräkningstyp ärIEnumerator
-gränssnittet. Om identifierarenvar
anges som lokal_variabeltyp , är elementtypendynamic
, annars är denobject
.I annat fall avgör du om typen
X
har en lämpligGetEnumerator
metod:
- Utför medlemssökning på typen
X
med identifierarenGetEnumerator
och inga typargument. Om medlemssökningen inte ger någon matchning, eller om den skapar en tvetydighet eller skapar en matchning som inte är en metodgrupp, kontrollerar du om det finns ett uppräkningsbart gränssnitt enligt beskrivningen nedan. Vi rekommenderar att en varning utfärdas om medlemssökningen genererar något annat än en metodgrupp eller ingen matchning.- Utför överbelastningsmatchning med hjälp av den resulterande metodgruppen och en tom argumentlista. Om överbelastningsmatchning inte resulterar i några tillämpliga metoder, resulterar i en tvetydighet eller resulterar i en enda bästa metod, men den metoden antingen är statisk eller inte offentlig, kontrollerar du om det finns ett uppräkningsbart gränssnitt enligt beskrivningen nedan. Vi rekommenderar att en varning utfärdas ifall överbelastningsupplösning ger något annat än en entydig offentlig instansmetod eller inga metoder är tillämpliga.
- Om returtypen
E
av metodenGetEnumerator
inte är en klass-, struct- eller gränssnittstyp genereras ett fel och inga ytterligare steg vidtas.- Medlemssökning utförs på
E
med identifierarenCurrent
och inga typargument. Om medlemssökningen inte ger någon matchning är resultatet ett fel eller resultatet är något annat än en offentlig instansegenskap som tillåter läsning, ett fel skapas och inga ytterligare åtgärder vidtas.- Medlemssökning utförs på
E
med identifierarenMoveNext
och inga typargument. Om medlemssökningen inte ger någon matchning är resultatet ett fel, eller resultatet är något annat än en metodgrupp, ett fel genereras och inga ytterligare åtgärder vidtas.- Överbelastningslösning utförs på metodgruppen med en tom argumentlista. Om överbelastningsmatchning inte resulterar i några tillämpliga metoder, resulterar i en tvetydighet eller resulterar i en enda bästa metod, men den metoden är antingen statisk eller inte offentlig, eller dess returtyp är inte
bool
genereras ett fel och inga ytterligare åtgärder vidtas.- Den samlingstypen är
X
, uppräkningstypen ärE
och -elementtypen är typen av egenskap förCurrent
.Annars kontrollerar du om det finns ett uppräkningsbart gränssnitt:
- Om det bland alla typer
Ti
för vilka det finns en implicit konvertering frånX
tillIEnumerable<Ti>
finns det en unik typT
så attT
intedynamic
och för alla andraTi
finns det en implicit konvertering frånIEnumerable<T>
tillIEnumerable<Ti>
, är samlingstyp gränssnittetIEnumerable<T>
, uppräkningstyp är gränssnittetIEnumerator<T>
och elementtypen ärT
.- Om det finns fler än en sådan typ
T
genereras annars ett fel och inga ytterligare åtgärder vidtas.- Om det annars finns en implicit konvertering från
X
tillSystem.Collections.IEnumerable
-gränssnittet är -samlingstypen det här gränssnittet uppräkningstypen gränssnittetSystem.Collections.IEnumerator
och -elementtypen ärobject
.I annat fall avgör du om typen "X" har en lämplig
GetEnumerator
tilläggsmetod:
- Utför tilläggsmetodsökning på typen
X
med identifierarenGetEnumerator
. Om medlemssökningen inte genererar någon matchning, eller om den skapar en tvetydighet, eller skapar en matchning som inte är en metodgrupp, genereras ett fel och inga ytterligare åtgärder vidtas. Vi rekommenderar att en varning utfärdas om medlemssökningen genererar något annat än en metodgrupp eller ingen träff.- Utför överbelastningsmatchning med hjälp av den resulterande metodgruppen och ett enda argument av typen
X
. Om överbelastningsmatchning inte ger några tillämpliga metoder, resulterar i en tvetydighet eller resulterar i en enda bästa metod, men den metoden inte är tillgänglig, genereras ett fel utan ytterligare åtgärder.
- Den här lösningen tillåter att det första argumentet skickas av referens om
X
är en structtyp och referenstypen ärin
.- Om returtypen
E
av metodenGetEnumerator
inte är en klass-, struct- eller gränssnittstyp genereras ett fel och inga ytterligare steg vidtas.- Medlemssökning utförs på
E
med identifierarenCurrent
och inga typargument. Om medlemssökningen inte ger någon matchning är resultatet ett fel eller resultatet är något annat än en offentlig instansegenskap som tillåter läsning, ett fel skapas och inga ytterligare åtgärder vidtas.- Medlemssökning utförs på
E
med identifierarenMoveNext
och inga typargument. Om medlemssökningen inte ger någon matchning är resultatet ett fel, eller resultatet är något annat än en metodgrupp, ett fel genereras och inga ytterligare åtgärder vidtas.- Överbelastningslösning utförs på metodgruppen med en tom argumentlista. Om överbelastningsmatchning inte resulterar i några tillämpliga metoder, resulterar i en tvetydighet eller resulterar i en enda bästa metod, men den metoden är antingen statisk eller inte offentlig, eller dess returtyp är inte
bool
genereras ett fel och inga ytterligare åtgärder vidtas.- Den samlingstypen är
X
, uppräkningstypen ärE
och -elementtypen är typen av egenskap förCurrent
.Annars genereras ett fel och inga ytterligare åtgärder vidtas.
För await foreach
ändras reglerna på liknande sätt. Den enda ändring som krävs för den specifikationen är att ta bort den Extension methods do not contribute.
raden från beskrivningen, eftersom resten av specifikationen baseras på ovanstående regler med olika namn som ersätts med mönstermetoderna.
Nackdelar
Varje ändring lägger till ytterligare komplexitet i språket, vilket kan leda till att saker som inte är utformade för att foreach
ed kan bli foreach
ed, som Range
.
Alternativ
Gör ingenting.
Olösta frågor
Ingen just nu.
C# feature specifications