Cómo utilizar Yield en programación

En este post vamos a ver una palabra clave dentro de .net que todos sabemos que existe, pero casi nunca la utilizamos. 

 

Y esta es la keyword o palabra clave yield, la cual fue introducida en C# 2, en este post, veremos qué realiza la palabra clave yield, cómo utilizarla y por supuesto un pequeño ejemplo.

 

 

1 - Para qué sirve yield en programación

En programación utilizamos yield para evitar tener que crear colecciones de datos temporales. 

Eso sí, cuando utilizamos yield return debemos devolver un IEnumerable<T> ya que necesitamos utilizar la interfaz IEnumerator.

 

Podemos denominar colecciones de datos temporales a aquellas listas  que simplemente creamos para reutilizarlas justo después en un bucle foreach o similar.

public IEnumerable<string> FiltrarCochesGetNombres(List<Coche> coches)
{
    List<string> nombreCoches = new List<string>();
    foreach (Coche coche in coches)
    {
        if (coche.Marca == MarcaCcohe.Opel)
        {
            nombreCoches.Add(coche.Modelo);
        }
    }
    return nombreCoches;
}

Observamos que únicamente estamos devolviendo los modelos de la marca Opel.

 

Sí la lógica de nuestro código dice que vamos a tratar con esa información después y que no la necesitamos agrupada, podemos convertir este método para utilizar yield return:

public IEnumerable<string> FiltrarCochesGetNombresYield(List<Coche> coches)
{
    foreach (Coche coche in coches)
    {
        if (coche.Marca == MarcaCcohe.Opel)
        {
            yield return coche.Modelo;
        }
    }
}

 

 

2 - Cómo funciona yield return

He indicado antes que es raro o poco común ver código que contiene métodos con yield, y esto es porque su ejecución parece “mágica” pero no lo es. 

 

Lo que el operador yield realiza es pausar la ejecución de la iteración y devolver el valor al método que realiza la llamada para que este continúe con su ejecución y cuando termine volverá al siguiente punto del iterador (el que está en el método con yield return). 

public void Ejemplo()
{
    List<Coche> coches = new List<Coche>()
    {
        new Coche(MarcaCcohe.Audi, "A3"),
        new Coche(MarcaCcohe.Audi, "A5"),
        new Coche(MarcaCcohe.Opel, "Vectra"),
        new Coche(MarcaCcohe.Opel, "Astra"),
    };


    foreach (string modelo in FiltrarCochesGetNombresYield(coches))
    {
        Console.WriteLine($"El modelo del cohce es {modelo}");
    }

}

yield return explicado

 

nota: cuando utilzamos .Select() en un comando linq es como si hicieramos yield return

public IEnumerable<string> FiltrarCochesGetNombresYield(List<Coche> coches)
{
    return coches.Where(a => a.Marca == MarcaCcohe.Opel).Select(a => a.Modelo);
}

Siempre y cuando estemos devolviendo IEnumerable<T> y no List<T>.

 

Lo cual pues siempre ayuda a mejorar el rendimiento, ya sabéis los que me seguís de  normal que soy bastante tiquismiquis con el rendimiento.

 

 

3 - Ejemplo yield return en c# 

Personalmente tuve la fortuna de encontrarme con una pregunta en una entrevista que hice, la cual se resolvió, o bueno, una solución era utilizar yield return.

 

El problema era el siguiente: 

Implementar una función que recibe por parametro un IEnumerable<T> y un batch size. había que dividir ese IEnumerable para devolver IEnumerable<List<T>> donde cada uno de los List<T> es igual o menor que el batch size:

public static IEnumerable<List<T>> Batch<T>(this IEnumerable<T> enumerable, int batchCount)
{
    // Code...
}

 

Y este fué el resultado final:

public static IEnumerable<List<T>> Batch<T>(this IEnumerable<T> enumerable, int batchCount)
{
    using (var enumerator = enumerable.GetEnumerator()) //get iteration for the Ienumerable.
    {
        while (enumerator.MoveNext())
        {
            //(re)start the values for the loop.
            List<T> result = new List<T>();
            var position = 0;
            do
            {
                result.Add(enumerator.Current);//add current iteration
                position++;

            } while (position < batchCount && enumerator.MoveNext());

            yield return result;
        }
    }
}

 

 

 

Conclusión

  • Cuando utilizamos yield return lo que hacemos es parar la ejecución del bucle que contiene el yield return para continuar con el método que lo ha llamado.
  • Por este motivo yield return nos puede dar mejoras en el rendimiento y el uso de la ram lo cual siempre es importante.
  • Podemos utilizar yield break para “romper el bucle” y así lo podemos utilizar dentro de un bloque try{} catch{} pero no en un finally.
  • Una vez nos acostumbramos a utilizarlo, podemos ver que es muy útil y muy potente, pero desafortunadamente no es muy común. 

 


Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2024 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café