yield (Riferimenti per C#)

Quando si usa la yieldyield in un'istruzione, si indica che il metodo, l'operatore o la funzione di accesso get in cui appare è un iteratore. Utilizzando yield per definire un iteratore, si elimina la necessità di una classe esplicita aggiuntiva (la classe che contiene lo stato per un'enumerazione, vedere IEnumerator<T> per un esempio) quando si implementano i modelli IEnumerable e di IEnumerator per un tipo di raccolta personalizzato.

Nell'esempio seguente vengono illustrate le due forme dell'istruzione yield.

yield return <expression>;
yield break;

Commenti

Si utilizza un'istruzione yield return per restituire un elemento alla volta.

La sequenza restituita da un metodo iteratore può essere usata con un'istruzione foreach o una query LINQ. Ogni iterazione del ciclo foreach chiama il metodo iteratore. Quando si raggiunge un'istruzione yield return nel metodo iteratore, viene restituito expression e viene mantenuta la posizione corrente nel codice. L'esecuzione viene riavviata a partire da quella posizione la volta successiva che viene chiamata la funzione iteratore.

Quando l'iteratore restituisce System.Collections.Generic.IAsyncEnumerable<T>, tale sequenza può essere utilizzata in modo asincrono usando System.Collections.Generic.IAsyncEnumerable<T> . L'iterazione del ciclo è analoga all'istruzione foreach . La differenza è che ogni iterazione può essere sospesa per un'operazione asincrona prima di restituire l'espressione per l'elemento successivo.

È possibile utilizzare un'istruzione yield break per terminare l'iterazione.

Per altre informazioni sugli iteratori, vedere Iteratori.

Metodi e funzioni di accesso get dell'iteratore

La dichiarazione di un iteratore deve soddisfare i seguenti requisiti:

Il tipo yield di un iteratore che restituisce IEnumerable o IEnumerator è object. Se l'iteratore IEnumerable<T> restituisce o IEnumerator<T>, deve essere presente una conversione implicita dal tipo dell'espressione nell'istruzione yield return al parametro di tipo generico.

Non è possibile includere un'istruzione yield return o yield break in:

Gestione delle eccezioni

Un'istruzione yield return non può essere inclusa in un blocco try-catch. Un'istruzione yield return può essere inclusa nel blocco try di un'istruzione try-finally.

Un'istruzione yield break può essere inclusa in un blocco try o in un blocco catch ma non in un blocco finally.

Se il foreach corpo o await foreach (all'esterno del metodo iteratore) genera un'eccezione, finally viene eseguito un blocco nel metodo iteratore.

Implementazione tecnica

Il codice seguente restituisce IEnumerable<string> da un metodo iteratore e quindi scorre i relativi elementi.

IEnumerable<string> elements = MyIteratorMethod();
foreach (string element in elements)
{
   ...
}

La chiamata a MyIteratorMethod non esegue il corpo del metodo. La chiamata restituisce invece IEnumerable<string> nella variabile elements.

In un'iterazione del ciclo foreach, il metodo MoveNext viene chiamato per elements. Questa chiamata esegue il corpo di MyIteratorMethod fino a quando non viene raggiunta l'istruzione yield return successiva. L'espressione restituita dall'istruzione yield return determina non solo il valore della variabile element per l'utilizzo da parte del corpo del ciclo, ma anche la proprietà Current di elements, che è IEnumerable<string>.

In ogni iterazione successiva del ciclo foreach, l'esecuzione del corpo dell'iteratore continua da dove è stata interrotta, fermandosi ancora quando raggiunge un'istruzione yield return. Il ciclo foreach termina quando si raggiunge la fine del metodo iteratore o un'istruzione yield break.

Il codice seguente restituisce IAsyncEnumerable<string> da un metodo iteratore e quindi scorre i relativi elementi.

IAsyncEnumerable<string> elements = MyAsyncIteratorMethod();
await foreach (string element in elements)
{
   // ...
}

In un'iterazione del ciclo await foreach, il metodo IAsyncEnumerator<T>.MoveNextAsync viene chiamato per elements. Il System.Threading.Tasks.ValueTask<TResult> valore restituito da MoveNext viene completato quando viene raggiunto yield return il successivo.

In ogni iterazione successiva del ciclo await foreach, l'esecuzione del corpo dell'iteratore continua da dove è stata interrotta, fermandosi ancora quando raggiunge un'istruzione yield return. Il ciclo await foreach termina quando si raggiunge la fine del metodo iteratore o un'istruzione yield break.

Esempio

L'esempio seguente contiene un'istruzione yield return all'interno di un ciclo for. Ogni iterazione del corpo dell'istruzione foreach nel metodo Main crea una chiamata alla funzione iteratore Power. Ogni chiamata alla funzione iteratore procede fino alla prossima esecuzione dell'istruzione yield return, che si verifica durante l'iterazione successiva del ciclo for.

Il tipo restituito del metodo iteratore è IEnumerable, ovvero un tipo di interfaccia iteratore. Quando il metodo iteratore viene chiamato, restituisce un oggetto enumerabile che contiene le potenze di un numero.

public class PowersOf2
{
    static void Main()
    {
        // Display powers of 2 up to the exponent of 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }

    public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
    {
        int result = 1;

        for (int i = 0; i < exponent; i++)
        {
            result = result * number;
            yield return result;
        }
    }

    // Output: 2 4 8 16 32 64 128 256
}

Nell'esempio seguente viene illustrata una funzione di accesso get che è un iteratore. Nell'esempio, ogni istruzione yield return restituisce un'istanza di una classe definita dall'utente.

public static class GalaxyClass
{
    public static void ShowGalaxies()
    {
        var theGalaxies = new Galaxies();
        foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy)
        {
            Debug.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString());
        }
    }

    public class Galaxies
    {

        public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy
        {
            get
            {
                yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
                yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
                yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
                yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
            }
        }
    }

    public class Galaxy
    {
        public String Name { get; set; }
        public int MegaLightYears { get; set; }
    }
}

Specifiche del linguaggio C#

Per altre informazioni, vedere Specifica del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedi anche