lunes, 4 de agosto de 2014

Enumeradores en C#

Índice

0. Introducción
1. Enumeración de Secuencia de Valores
2. Interfaz IEnumerator
3. Interfaz IEnumerable
4. Ejemplo de Uso
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Ya hemos tratado la sentencia de repetición foreach y sabemos que se trata de un ciclo útil para recorrer (o iterar) los elementos (valores) de una secuencia: arreglo o colección. Estas estructuras o colecciones se caracterizan por implementar las interfaz IEnumerable (System.Collections) o IEnumerable<T;> (System.Collections.Generic); vamos aprovechar este conocimiento para ir más a fondo de la implementación de enumeradores usando estas interfaces. Crearemos un ejemplo en el que se demostrará su utilidad: definición de una estructura de datos y el enumerador de los valores de esta estructura de datos.

1. Enumeración de Secuencia de Valores

Empecemos por definir en qué consiste una secuencia de valores. En un principio, podemos pensar en un grupo de valores que pueden ser enumerados (contados y denominados). Esta enumeración de elementos se caracteriza por ser de solo lectura, y ocurre en una sola dirección [1].

Los elementos necesarios para implementar el uso de un enumerador sobre una estructura de datos consistente en el uso de las siguientes interfaces:
  • System.Collections.IEnumerator, o la versión genérica (cfr. Tipos GenéricosIEnumerator<T> (System.Collections.Generic).
  • System.Collections.Inumerable, o la versión genérica System.Collections.Generic.IEnumerable<T>.
Veamos cada una de estas interfaces con un poco más de detalle.

2. Interfaz IEnumerator

La interfaz IEnumerator [3] es implementada por parte de las clases de objetos encargados del recorrido de los valores de una estructura (arreglo o colección).

Los miembros de esta interfaz son 3. A saber [3]:
  • Propiedades:
    • Current: Elemento actual en la colección.
  • Métodos:
    • MoveNext: El enumerador avanza al siguiente elemento de la colección.
    • Reset: El enumerador se ubica en la posición inicial. (Consiste en el elemento anterior al primer elemento elemento de la colección: -1.)
Esta interfaz cuenta una versión para tipos genéricos en el nombre de espacios System.Collections.GenericIEnumerator<T> [4].

En la sección 4 prepararemos un ejemplo para demostrar el uso de esta interfaz para comprender su utilidad.

3. Interfaz IEnumerable

La interfaz IEnumerable [5] (System.Collections) o su versión para tipos genéricos System.Collections.IEnumerable<T> [6] es implementada por estructuras de datos que requieren que sus elementos sean enumerados (iterados), por ejemplo, a través de un ciclo foreach (cfr. Sentencias en C#).

Esta interfaz cuenta con los siguientes miembros estándar:
  • Métodos:
    • GetEnumerator: Este método retorna un objeto para iterar la colección o arreglo. (Ver sección 2.)

4. Ejemplo de Uso

En este ejemplo implementaremos las interfaces no genéricas IEnumerable y IEnumerator sobre dos clases que cuentan con la implementación concreta para enumerar y especificar un objeto enumerador:
  • Gente: Estructura de datos para ser iterada.
  • GenteEnum: Enumerador de los elementos (valores) de la estructura de datos Gente.
En las líneas 7-26 se define la clase Persona con las propiedades Nombre y Apellido.


En la estructura de datos Gente (líneas 29-54) implementa la interfaz IEnumerable para permitir el recorrido o la iteración por cada uno de los elementos agregados a la estructura de datos. Sobre las líneas 45-48 se hace la implementación explícita del método GetEnumerator. La lógica dentro del cuerpo de este método invoca al método GetEnumerator, el cual corresponde con la implementación implícita del método GetEnumerator (líneas 50-53).



Por otra parte, la clase GenteEnum (líneas 57-109) implementa la interfaz GetEnumerator. Esta clase se convertirá en la clase especializada para recorrer los elementos de la estructura Gente. Miembros de esta clase:
  • Propiedades:
    • Current (líneas 72-78): Para obtener el elemento actual de la iteración de la estructura Gente.
  • Métodos:
    • MoveNext (líneas 97-101): Verifica que la estructura Gente aún contiene elementos por iterar.
    • Reset (líneas 105-108): Reestablece el enumerador a la posición inicial.
Compilador:

  1. csc /target:exe UsoEnumeradores.cs

Ejecución assembly:


  1. .\UsoEnumeradores.exe

Prueba de ejecución (ideone.com).

Prueba de ejecución (local):
Ejecución assembly UsoEnumeradores.exe

5. Conclusiones

Demostramos que los enumeradores en C# pueden ser implementandos de manera muy simple y directa a través de las interfaces IEnumerable y IEnumerator. Como vimos cada una de estas interfaces contienen el conjunto de propiedades y métodos para convertir a una clase en una estructura con elementos para ser recorridos, y otra clase especializada para llevar a cabo la tarea de iteración o recorrido de los elementos de la estructura. En el próximo artículo aprenderemos acerca de los inicializadores de colecciones.

6. Glosario

  • Clase
  • Enumeración
  • Enumerador
  • Estructura de datos
  • Iteración
  • Iterador
  • Recorrido

7. Literatura & Enlaces

[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2]: Tipos Genéricos en C# - Parte 1: Introducción | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2014/05/genericos-en-c-parte-1-introduccion.html
[3]: IEnumerator Interface (System.Collections) - http://msdn.microsoft.com/en-us/library/system.collections.ienumerator%28v=vs.110%29.aspx
[4]: IEnumerator(T) Interface (System.Collections.Generic) - http://msdn.microsoft.com/en-us/library/78dfe2yb%28v=vs.110%29.aspx
[5]: IEnumerable Interface (System.Collections) - http://msdn.microsoft.com/en-us/library/system.collections.ienumerable%28v=vs.110%29.aspx
[6]: IEnumerable(T) Interface (System.Collections.Generic) - http://msdn.microsoft.com/en-us/library/9eekhta0%28v=vs.110%29.aspx
[7]: Sentencias en C# - Parte 2 | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2013/10/sentencias-en-c-parte-2.html
[8]: Understanding IEnumerable and the iterator design pattern | Monty's Gush - http://petemontgomery.wordpress.com/2010/12/08/understanding-ienumerable-iterator-pattern/


J

2 comentarios:

  1. Hola John,

    Excelente documento. Solo no me queda claro la utilizacion de una expresión en el return del método MoveNext de la clase GenteEnum. Esa expresión es "return ( posicion < gente.Length)". ¿Qué significa? ¿ return generará una excepción si posición es mayor que gente.Lenght? Estoy aprendiendo C# por mi cuenta y vuestros tutoriales son mi material principal. Un saludo desde España y gracias por la atención. ernestosuscriptor@hotmail.es

    ResponderEliminar
  2. Hola:

    El método MoveNext podríamos calificarlo de interrogador (validador). Esto quiere decir que en caso de que no existan más elementos por recorrer en la enumeración, el método retornará False.

    Saludos.

    ResponderEliminar

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.