Condividi tramite


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 language design meeting (LDM) pertinenti.

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 §13.9.5 viene modificata con il seguente testo:

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 da X all'interfaccia IEnumerable (poiché System.Array implementa questa interfaccia). Il tipo di raccolta è l'interfaccia IEnumerable, il tipo di enumeratore è l'interfaccia IEnumerator e il tipo di elemento è il tipo di elemento del tipo di matrice X.

  • Se il tipo X dell'espressione è dynamic viene eseguita una conversione implicita da expression all'interfaccia IEnumerable (§10.2.10). Il tipo di raccolta è l'interfaccia IEnumerable e il tipo di enumeratore è l'interfaccia IEnumerator. Se l'identificatore var 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 di GetEnumerator appropriato:

    • Eseguire la ricerca dei membri nel tipo X con identificatore GetEnumerator 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 metodo GetEnumerator 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'identificatore Current 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'identificatore MoveNext 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 è Ee 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 da X a IEnumerable<Ti>, esiste un tipo univoco T in modo che T non sia dynamic e per tutte le altre Ti sia presente una conversione implicita da IEnumerable<T> a IEnumerable<Ti>, il tipo di raccolta è l'interfaccia IEnumerable<T>, il tipo di enumeratore è l'interfaccia IEnumerator<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'interfaccia System.Collections.IEnumerable, il tipo di raccolta è questa interfaccia, il tipo di enumeratore è l'interfaccia System.Collections.IEnumeratore 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 identificatore GetEnumerator. 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 metodo GetEnumerator 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'identificatore Current 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'identificatore MoveNext 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 è Ee 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 foreachdi essere foreach, ad esempio Range.

Alternative

Non fare nulla.

Domande non risolte

Nessuno a questo punto.