Pensemos por un momento cómo podemos construir en C# 1.0 o 1.1, una clase contenedora de datos que se pueda utilizar con la construcción foreach para iterar por los elementos que contiene...

Para empezar la clase debe implementar la interface IEnumerable. Esto tampoco supone mucho trabajo ya que, al fin y al cabo, sólo se debe implementar un método, GetEnumerator(). Ahí se empieza complicar la cosa un poco ya que este método devolverá un objeto que implementa la interfaz IEnumerator y que nosotros debemos definir también. La implementación de esta clase es algo más compleja y además debe mantener una referencia al objeto enumerable original.

Ya de por sí, como podemos comprobar, se trata de algo bastante tedioso. Pero es que además de eso en algunos casos es algo muy complicado de hacer. Por ejemplo, si queremos implementar una clase enumerable que contenga los nodos de una jerarquía (un árbol de carpetas, por ejemplo) y que, enumerándolo con foreach, nos devuelva por el orden correcto de visualización todos los elementos del árbol en todos los niveles. Esto ya es algo más complicado y farragoso: hay que meterse en procedimientos recursivos y coordinar las llamadas a Current(), MoveNext() y Reset(). No digo que no se pueda hacer ni mucho menos. Sólo digo que es más complicado todavía.

Los Iteradores de C# 2.0: facilit√°ndonos la vida.

Los nuevos iteradores de C# 2.0 nos permiten crear clases iterables con foreach pero sin apenas esfuerzo y complicación. Además permiten iterar por colecciones de elementos más complejas que una simple lista de elementos, como por ejemplo el árbol jerárquico del que hablaba más atrás.

Imaginemos una clase Contenedor que almacena una lista de objetos de tipo indeterminado de momento (aqu√≠ haremos uso de tipos gen√©ricos que coment√© en un post hace unos d√≠as). La definiremos sin especificar qu√© tipos de elemento albergar√° y as√≠ la hacemos m√°s √ļtil. Para coseguir que sea enumerable implementar√° la inerfaz IEnumerable, como antes, pero ahora en lugar de crear un objeto enumerador auxiliar emplearemos una nueva construcci√≥n. Ve√°moslo:

public class Contenedor : IEnumerable
{
    private Tipo[] datos;  //Aquí se almacenan los datos de la clase

    public Add(Tipo dato)... //Habría que implementarla, lo dejo fuera por claridad.

    public IEnumerator GetEnumerator()  //Aquí se implementa la interfaz
    {
        foreach (Tipo dato in datos)
        {
            yield dato;
        }
    }
}

Tal y como se observa en el c√≥digo anterior, la novedad estriba en el uso de la nueva palabra clave yield. √Čsta devuelve el elemento seleccionado y "congela" la ejecuci√≥n del c√≥digo (en este caso del bucle que la contiene) hasta que se realiza una nueva llamada al enumerador resultante, momento en el cual el bucle continua. Este es el efecto conseguido, en realidad el compilador hace el trabajo sucio por nosotros ahorr√°ndonos decenas de l√≠neas de c√≥digo. Muy √ļtil ¬Ņverdad?.

De hecho yield se puede usar de modo m√°s creativo a√ļn para hacer cosas, antes complicadas, de manera sencilla. yield se puede usar con cualquier m√©todo que devuelva un IEnumerator¬†(lo normal), o incluso si devuelve un IEnumerable. esto abre nuevas posibiliddes. Por ejemplo, imaginemos que queremos iterar por un subconjunto de datos de una clase contenedora. Podemos conseguirlo devolviendo un IEnumerable a√Īadi√©ndole este m√©todo a la clase anterior:

public IEnumerable<Tipo> SubConjunto(int desde, int hasta)
{
    while (desde < hasta)
    {
        yield datos[desde++];
    }
}

Como vemos lo √ļnico que se hace es recorrer los elementos desde el elemento inicial al final devolvi√©ndolos mientras tanto y "deteniendo" la ejecuci√≥n del bucle con yield hasta la siguiente llamada a la enumeraci√≥n. Es infinitamente m√°s f√°cil que antes.

El interesado podr√° encontrar un estupendo art√≠culo a fondo sobre este tema en el n√ļmero 7 de DotnetMania, de Septiembre de 2004. Adem√°s de explicarlo a fondo los autores (Miguel Katrib y Mario del Valle), en un alarde de virtuosismo, se curran un equivalente a esta t√©cnica hecha con multi-subproceso, y que funciona en la versi√≥n actual de C#. Muy recomendable. El c√≥digo asociado con esta implementaci√≥n se puede descargar desde aqu√≠.

💪🏻 ¬ŅEste post te ha ayudado?, ¬Ņhas aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor