Condividi tramite


yield (Riferimenti per C#)

Quando si utilizza la parola chiave yield 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 per un esempio) quando si implementano i modelli IEnumerator e di IEnumerable per un tipo di raccolta personalizzato.

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

yield return <expression>;
yield break;

Note

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

Si utilizza un metodo iteratore tramite 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.

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

Per ulteriori informazioni sugli iteratori, vedere Iteratori (C# e Visual Basic).

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 restituisce IEnumerable o IEnumerator, 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 nei metodi che presentano le seguenti caratteristiche:

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 corpo di foreach (esterno al metodo iteratore) genera un'eccezione, viene eseguito un blocco finally 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 dal corpo del ciclo, ma anche la proprietà Current degli elementi, ovvero 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.

Esempio

L'esempio seguente contiene un'istruzione yield return all'interno di un ciclo for. Ogni iterazione del corpo dell'istruzione foreach in Process 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 la Specifiche del linguaggio C#. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.

Vedere anche

Riferimenti

foreach, in (Riferimenti per C#)

Concetti

Guida per programmatori C#

Altre risorse

Riferimenti per C#

Iteratori (C# e Visual Basic)