Hacer que una clase de Visual C# se pueda usar en una instrucción foreach
En este artículo se muestra cómo usar las IEnumerable interfaces y IEnumerator para crear una clase que se puede usar en una foreach instrucción .
Versión del producto original: Visual Studio
Número de KB original: 322022
Interfaz IEnumerator
IEnumerable y IEnumerator se usan con frecuencia juntos. Aunque estas interfaces son similares (y tienen nombres similares), tienen propósitos diferentes.
La IEnumerator interfaz proporciona funcionalidad iterativa para una colección que es interna para una clase. IEnumerator requiere que implemente tres métodos:
El
MoveNextmétodo , que incrementa el índice de colección en 1 y devuelve un bool que indica si se ha alcanzado el final de la colección.El
Resetmétodo , que restablece el índice de colección a su valor inicial de -1. Esto invalida el enumerador.Método
Current, que devuelve el objeto actual enposition.public bool MoveNext() { position++; return (position < carlist.Length); } public void Reset() { position = -1; } public object Current { get { return carlist[position];} }
Interfaz IEnumerable
La IEnumerable interfaz proporciona compatibilidad con la foreach iteración. IEnumerable requiere que implemente el GetEnumerator método .
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
Cuándo usar la interfaz
Inicialmente, es posible que le resulte confuso usar estas interfaces. La IEnumerator interfaz proporciona iteración sobre un objeto de tipo colección en una clase. La IEnumerable interfaz permite la enumeración mediante un foreach bucle . Sin embargo, el GetEmunerator método de la IEnumerable interfaz devuelve una IEnumerator interfaz. Por lo tanto, para implementar IEnumerable, también debe implementar IEnumerator. Si no implementa IEnumerator, no puede convertir el valor devuelto desde el GetEnumerator método de IEnumerable a la IEnumerator interfaz.
En resumen, el uso de IEnumerable requiere que la clase implemente IEnumerator. Si desea proporcionar compatibilidad con foreach, implemente ambas interfaces.
Ejemplo paso a paso
En el ejemplo siguiente se muestra cómo usar estas interfaces. En este ejemplo, las IEnumerator interfaces y IEnumerable se usan en una clase denominada cars. La cars clase tiene una matriz interna de car objetos. Las aplicaciones cliente pueden enumerarse a través de esta matriz interna mediante una foreach construcción debido a la implementación de estas dos interfaces.
Siga estos pasos para crear un nuevo proyecto de aplicación de consola en Visual C#:
- Inicie Microsoft Visual Studio .NET o Visual Studio.
- En el menú Archivo, elija Nuevo y, a continuación, haga clic en Proyecto.
- Haga clic en Proyectos en Visual C# en Tipos de proyecto y luego haga clic en Aplicación de consola en Plantillas.
- En el cuadro Nombre , escriba ConsoleEnum.
Cambie el nombre de Class1.cs a host.cs y, a continuación, reemplace el código de host.cs por el código siguiente:
using System; namespace ConsoleEnum { class host { [STAThread] static void Main(string[] args) { cars C = new cars(); Console.WriteLine("\nInternal Collection (Unsorted - IEnumerable,Enumerator)\n"); foreach(car c in C) Console.WriteLine(c.Make + "\t\t" + c.Year); Console.ReadLine(); } } }En el menú Project, haga clic en Agregar clase y, a continuación, escriba car en el cuadro Nombre.
Reemplace el código de car.cs por el código siguiente:
using System; using System.Collections; namespace ConsoleEnum { public class car { private int year; private string make; public car(string Make,int Year) { make=Make; year=Year; } public int Year { get {return year;} set {year=value;} } public string Make { get {return make;} set {make=value;} } }//end class }//end namespaceEn el menú Project, haga clic en Agregar clase para agregar otra clase al proyecto y, a continuación, escriba cars en el cuadro Nombre.
Reemplace el código de cars.cs por el código siguiente:
using System; using System.Collections; namespace ConsoleEnum { public class cars : IEnumerator,IEnumerable { private car[] carlist; int position = -1; //Create internal array in constructor. public cars() { carlist= new car[6] { new car("Ford",1992), new car("Fiat",1988), new car("Buick",1932), new car("Ford",1932), new car("Dodge",1999), new car("Honda",1977) }; } //IEnumerator and IEnumerable require these methods. public IEnumerator GetEnumerator() { return (IEnumerator)this; } //IEnumerator public bool MoveNext() { position++; return (position < carlist.Length); } //IEnumerable public void Reset() { position = -1; } //IEnumerable public object Current { get { return carlist[position];} } } }Ejecute el proyecto.
La siguiente salida aparece en la ventana Consola :
Ford 1992
Fiat 1988
Buick 1932
Ford 1932
Dodge 1999
Honda 1977
Procedimientos recomendados
El ejemplo de este artículo se mantiene lo más sencillo posible para explicar mejor el uso de estas interfaces. Para que el código sea más sólido y para asegurarse de que el código usa las directrices de procedimientos recomendados actuales, modifique el código de la siguiente manera:
- Implemente
IEnumeratoren una clase anidada para que pueda crear varios enumeradores. - Proporcione el control de excepciones para el
Currentmétodo deIEnumerator. Si cambia el contenido de la colección, se llama alresetmétodo . Como resultado, el enumerador actual se invalida y recibe unaIndexOutOfRangeExceptionexcepción. Otras circunstancias también pueden provocar esta excepción. Por lo tanto, implemente unTry...Catchbloque para detectar esta excepción y generar unaInvalidOperationExceptionexcepción.
using System;
using System.Collections;
namespace ConsoleEnum
{
public class cars : IEnumerable
{
private car[] carlist;
//Create internal array in constructor.
public cars()
{
carlist= new car[6]
{
new car("Ford",1992),
new car("Fiat",1988),
new car("Buick",1932),
new car("Ford",1932),
new car("Dodge",1999),
new car("Honda",1977)
};
}
//private enumerator class
private class MyEnumerator:IEnumerator
{
public car[] carlist;
int position = -1;
//constructor
public MyEnumerator(car[] list)
{
carlist=list;
}
private IEnumerator getEnumerator()
{
return (IEnumerator)this;
}
//IEnumerator
public bool MoveNext()
{
position++;
return (position < carlist.Length);
}
//IEnumerator
public void Reset()
{
position = -1;
}
//IEnumerator
public object Current
{
get
{
try
{
return carlist[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
} //end nested class
public IEnumerator GetEnumerator()
{
return new MyEnumerator(carlist);
}
}
}