yield (Referencia de C#)

Cuando se usa la palabra clave yield en una instrucción, se indica que el método, el operador o el descriptor de acceso get en el que aparece es un iterador. Al usar yield para definir un iterador ya no es necesaria una clase adicional explícita (la clase que retiene el estado para una enumeración, consulte IEnumerator para ver un ejemplo) al implementar los patrones IEnumerable y IEnumerator para un tipo de colección personalizado.

En el ejemplo siguiente se muestran las dos formas de la instrucción yield.

yield return <expression>;
yield break;

Comentarios

Utilice una instrucción yield return para devolver cada elemento de uno en uno.

Para consumir un método iterador, use una instrucción foreach o una consulta LINQ. Cada iteración del bucle foreach llama al método iterador. Cuando se alcanza una instrucción yield return en el método iterador, se devuelve expression y se conserva la ubicación actual en el código. La ejecución se reinicia desde esa ubicación la próxima vez que se llama a la función del iterador.

Puede usar una instrucción yield break para finalizar la iteración.

Para obtener más información sobre los iteradores, vea Iteradores (C# y Visual Basic).

Métodos de iterador y descriptores de acceso get

La declaración de un iterador debe cumplir los requisitos siguientes:

El tipo yield de un iterador que devuelve IEnumerable o IEnumerator es object. Si el iterador devuelve IEnumerable o IEnumerator, debe haber una conversión implícita del tipo de la expresión en la instrucción yield return al parámetro de tipo genérico.

No se puede incluir una instrucción yield return ni yield break en los métodos que tengan las siguientes características:

Control de excepciones

Una instrucción yield return no puede encontrarse en un bloque try-catch. Una instrucción yield return puede encontrarse en el bloque try de una instrucción try-finally.

Una instrucción yield break puede encontrarse en un bloque try o un bloque catch, pero no en un bloque finally.

Si el cuerpo foreach (fuera del método iterador) produce una excepción, se ejecuta un bloque finally en el método iterador.

Implementación técnica

El código siguiente devuelve un valor IEnumerable<string> desde un método iterador y, a continuación, recorre sus elementos en iteración.

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

La llamada a MyIteratorMethod no ejecuta el cuerpo del método. En su lugar, la llamada devuelve un valor IEnumerable<string> en la variable elements.

En una iteración del bucle foreach, se llama al método MoveNext para elements. Esta llamada ejecuta el cuerpo de MyIteratorMethod hasta que se alcanza la siguiente instrucción yield return. La expresión devuelta por la instrucción yield return determina no solo el valor de la variable element para que la utilice el cuerpo del bucle, sino también la propiedad Current de elements, que es un valor IEnumerable<string>.

En cada iteración subsiguiente del bucle foreach, la ejecución del cuerpo del iterador continúa desde donde se dejó, deteniéndose de nuevo al alcanzar una instrucción yield return. El bucle foreach se completa al alcanzar el fin del método iterador o una instrucción yield break.

Ejemplo

El ejemplo siguiente tiene una instrucción yield return que está dentro de un bucle for. Cada iteración del cuerpo de instrucción foreach en Process crea una llamada a la función de iterador Power. Cada llamada a la función de iterador prosigue con la siguiente ejecución de la instrucción yield return, que se produce durante la siguiente iteración del bucle for.

El tipo de valor devuelto del método iterador es IEnumerable, que es un tipo de interfaz de iteradores. Cuando se llama al método iterador, este devuelve un objeto enumerable que contiene las potencias de un número.

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
}

En el ejemplo siguiente se muestra un descriptor de acceso get que es un iterador. En el ejemplo, cada una de las instrucciones yield return devuelve una instancia de una clase definida por el usuario.

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; }
    }
}

Especificación del lenguaje C#

Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.

Vea también

Referencia

foreach, in (Referencia de C#)

Conceptos

Guía de programación de C#

Otros recursos

Referencia de C#

Iteradores (C# y Visual Basic)