Supporto dell'estensione GetEnumerator
per i cicli di foreach
.
Nota
Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.
Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono acquisite nelle note
Ulteriori informazioni sul processo di adozione dei feature speclet nello standard della lingua C# sono disponibili nell'articolo sulle specifiche .
Sommario
Consentire ai cicli foreach
di riconoscere un metodo di estensione GetEnumerator
che soddisfa il modello foreach e iterare sull'espressione quando altrimenti sarebbe un errore.
Motivazione
Ciò porterà foreach
in linea con il modo in cui vengono implementate altre funzionalità in C#, tra cui la decostruzione asincrona e basata su modelli.
Progettazione dettagliata
La modifica delle specifiche è relativamente semplice. La sezione di
L'elaborazione in fase di compilazione di un'istruzione foreach determina innanzitutto il tipo di raccolta , il tipo di enumeratore e il tipo di elemento dell'espressione. Questa determinazione procede come segue:
Se il tipo
X
dell'espressione è un tipo di matrice, è presente una conversione implicita dei riferimenti daX
all'interfacciaIEnumerable
(poichéSystem.Array
implementa questa interfaccia). Il tipo di raccolta è l'interfacciaIEnumerable
, il tipo di enumeratore è l'interfacciaIEnumerator
e il tipo di elemento è il tipo di elemento del tipo di matriceX
.Se il tipo
X
dell'espressione èdynamic
viene eseguita una conversione implicita da expression all'interfacciaIEnumerable
(§10.2.10). Il tipo di raccolta è l'interfacciaIEnumerable
e il tipo di enumeratore è l'interfacciaIEnumerator
. Se l'identificatorevar
viene assegnato come local_variable_type, il tipo di elemento èdynamic
, in caso contrario èobject
.In caso contrario, determinare se il tipo
X
dispone di un metodo diGetEnumerator
appropriato:
- Eseguire la ricerca dei membri nel tipo
X
con identificatoreGetEnumerator
e senza argomenti di tipo. Se la ricerca del membro non produce una corrispondenza, o produce un'ambiguità, o produce una corrispondenza che non è un gruppo di metodi, verificate la presenza di un'interfaccia enumerabile come descritto di seguito. È consigliabile generare un avviso se la ricerca dei membri produce elementi tranne un gruppo di metodi o nessuna corrispondenza.- Eseguire la risoluzione dell'overload usando il gruppo di metodi risultante e un elenco di argomenti vuoto. Se la risoluzione dell'overload non produce metodi applicabili, genera un'ambiguità o restituisce un singolo metodo migliore, ma tale metodo è statico o non pubblico, verificare la presenza di un'interfaccia enumerabile come descritto di seguito. È consigliabile generare un avviso se la risoluzione dell'overload produce qualcosa di diverso da un metodo di istanza pubblica chiaro o nessun metodo che si possa applicare.
- Se il tipo restituito
E
del metodoGetEnumerator
non è una classe, uno struct o un tipo di interfaccia, viene generato un errore e non vengono eseguiti altri passaggi.- La ricerca dei membri viene eseguita su
E
con l'identificatoreCurrent
e senza argomenti di tipo. Se la ricerca del membro non produce corrispondenze, il risultato è un errore o il risultato è qualsiasi elemento tranne una proprietà dell'istanza pubblica che consente la lettura, viene generato un errore e non vengono eseguiti altri passaggi.- La ricerca dei membri viene eseguita su
E
con l'identificatoreMoveNext
e senza argomenti di tipo. Se la ricerca del membro non produce alcuna corrispondenza, il risultato è un errore o il risultato è qualsiasi elemento ad eccezione di un gruppo di metodi, viene generato un errore e non vengono eseguiti altri passaggi.- La risoluzione del sovraccarico viene eseguita sul gruppo di metodi con un elenco di parametri vuoto. Se la risoluzione dell'overload non restituisce metodi applicabili, genera un'ambiguità o restituisce un singolo metodo migliore, ma tale metodo è statico o non pubblico oppure il tipo restituito non è
bool
, viene generato un errore e non vengono eseguiti altri passaggi.- Il tipo di raccolta è
X
, il tipo di enumeratore èE
e il tipo di elemento è il tipo della proprietàCurrent
.In caso contrario, verificare la presenza di un'interfaccia enumerabile:
- Se tra tutti i tipi
Ti
per cui è presente una conversione implicita daX
aIEnumerable<Ti>
, esiste un tipo univocoT
in modo cheT
non siadynamic
e per tutte le altreTi
sia presente una conversione implicita daIEnumerable<T>
aIEnumerable<Ti>
, il tipo di raccolta è l'interfacciaIEnumerable<T>
, il tipo di enumeratore è l'interfacciaIEnumerator<T>
e il tipo di elemento èT
.- In caso contrario, se è presente più di un tipo di questo tipo
T
, viene generato un errore e non vengono eseguiti altri passaggi.- In caso contrario, se è presente una conversione implicita da
X
all'interfacciaSystem.Collections.IEnumerable
, il tipo di raccolta è questa interfaccia, il tipo di enumeratore è l'interfacciaSystem.Collections.IEnumerator
e il tipo di elemento èobject
.In caso contrario, determinare se il tipo 'X' dispone di un metodo di estensione
GetEnumerator
appropriato:
- Eseguire la ricerca del metodo di estensione nel tipo
X
con identificatoreGetEnumerator
. Se la ricerca del membro non produce una corrispondenza o produce un'ambiguità o produce una corrispondenza che non è un gruppo di metodi, viene generato un errore e non vengono eseguiti altri passaggi. È consigliabile emettere un avviso se la ricerca dei membri produce qualcosa diverso da un gruppo di metodi o nessuna corrispondenza.- Esegui la risoluzione dell'overload utilizzando il gruppo di metodi risultante e un singolo argomento di tipo
X
. Se la risoluzione dell'overload non produce metodi applicabili, genera un'ambiguità o restituisce un singolo metodo migliore, ma tale metodo non è accessibile, viene generato un errore senza ulteriori passaggi.
- Questa risoluzione consente di passare il primo argomento per ref se
X
è un tipo struct e il tipo ref èin
.- Se il tipo restituito
E
del metodoGetEnumerator
non è una classe, uno struct o un tipo di interfaccia, viene generato un errore e non vengono eseguiti altri passaggi.- La ricerca dei membri viene eseguita su
E
con l'identificatoreCurrent
e senza argomenti di tipo. Se la ricerca del membro non produce corrispondenze, il risultato è un errore o il risultato è qualsiasi elemento tranne una proprietà dell'istanza pubblica che consente la lettura, viene generato un errore e non vengono eseguiti altri passaggi.- La ricerca dei membri viene eseguita su
E
con l'identificatoreMoveNext
e senza argomenti di tipo. Se la ricerca del membro non produce alcuna corrispondenza, il risultato è un errore o il risultato è qualsiasi elemento ad eccezione di un gruppo di metodi, viene generato un errore e non vengono eseguiti altri passaggi.- La risoluzione dell'overload viene eseguita nel gruppo di metodi con un elenco di argomenti vuoto. Se la risoluzione dell'overload non restituisce metodi applicabili, genera un'ambiguità o restituisce un singolo metodo migliore, ma tale metodo è statico o non pubblico oppure il tipo restituito non è
bool
, viene generato un errore e non vengono eseguiti altri passaggi.- Il tipo di raccolta è
X
, il tipo di enumeratore èE
e il tipo di elemento è il tipo della proprietàCurrent
.In caso contrario, viene generato un errore e non vengono eseguiti altri passaggi.
Per await foreach
, le regole vengono modificate in modo analogo. L'unica modifica richiesta a tale specifica è rimuovere la riga Extension methods do not contribute.
dalla descrizione, poiché il resto di quella specifica si basa sulle regole sopra indicate con nomi diversi sostituiti ai metodi del pattern.
Svantaggi
Ogni modifica aggiunge complessità al linguaggio e potrebbe permettere agli elementi che non sono stati progettati per essere foreach
di essere foreach
, ad esempio Range
.
Alternative
Non fare nulla.
Domande non risolte
Nessuno a questo punto.
C# feature specifications