¿Alguien puede explicarme IEnumerable y IEnumerator? [cerrado]

272

¿Alguien puede explicarme IEnumerable y IEnumerator?

por ejemplo, ¿cuándo usarlo sobre foreach? ¿Cuál es la diferencia entre IEnumerable e IEnumerator? ¿Por qué necesitamos usarlo?

prodev42
fuente
55
Esta es la peor combinación de nombres desde Java y JavaScript
Matthew Lock
@MatthewLock, ¿puedes explicar a qué te refieres?
David Klempfner

Respuestas:

275

por ejemplo, ¿cuándo usarlo sobre foreach?

No utilizas IEnumerable"over" foreach. La implementación IEnumerablehace foreach posible el uso .

Cuando escribes código como:

foreach (Foo bar in baz)
{
   ...
}

es funcionalmente equivalente a escribir:

IEnumerator bat = baz.GetEnumerator();
while (bat.MoveNext())
{
   bar = (Foo)bat.Current
   ...
}

Por "funcionalmente equivalente", quiero decir que en realidad es en eso que el compilador convierte el código. No se puede utilizar foreachen bazeste ejemplo a menos baz implementos IEnumerable.

IEnumerablesignifica que bazimplementa el método

IEnumerator GetEnumerator()

El IEnumeratorobjeto que devuelve este método debe implementar los métodos.

bool MoveNext()

y

Object Current()

El primer método avanza al siguiente objeto en el IEnumerableobjeto que creó el enumerador, devolviendo falsesi está hecho, y el segundo devuelve el objeto actual.

Cualquier cosa en .Net que pueda iterar sobre implementos IEnumerable. Si está creando su propia clase, y aún no hereda de una clase que implementa IEnumerable, puede hacer que su clase sea utilizable en foreachdeclaraciones mediante la implementación IEnumerable(y creando una clase de enumerador que GetEnumeratordevolverá su nuevo método).

Robert Rossney
fuente
15
Creo que cuando el póster original decía "sobre foreach", se refería a "cuándo debería llamar a GetEnumerator () / MoveNext () explícitamente en lugar de usar un bucle foreach". Por lo que vale.
mqp
66
Ah, creo que tienes razón. Bueno, la respuesta está implícita en mi publicación: no importa, ya que eso es lo que hace el compilador de todos modos. Entonces, haga lo que sea más fácil, es decir, use foreach.
Robert Rossney
12
Esta respuesta no cuenta toda la historia. Los objetos enumerables no necesitan implementar IEnumerable; solo necesitan tener un método GetEnumerator que devuelva una instancia de un tipo que a su vez tenga un bool MoveNext()método y una Currentpropiedad de cualquier tipo. Este enfoque de "escritura de pato" se implementó en C # 1.0 como una forma de evitar el boxeo al enumerar colecciones de tipos de valor.
phoog
3
Con la explicación de arriba y trabajando a través de Workthrough: Implementando IEnumerable de (T) tienes grandes fuentes.
ruedi
44
¿Es esto algo así como un C ++ iterator?
Matt G
162

Las interfaces IEnumerable e IEnumerator

Para comenzar a examinar el proceso de implementación de las interfaces .NET existentes, primero veamos el rol de IEnumerable e IEnumerator. Recuerde que C # admite una palabra clave denominada foreach que le permite iterar sobre el contenido de cualquier tipo de matriz:

// Iterate over an array of items.
int[] myArrayOfInts = {10, 20, 30, 40};
foreach(int i in myArrayOfInts)
{
   Console.WriteLine(i);
}

Si bien puede parecer que solo los tipos de matriz pueden hacer uso de esta construcción, la verdad del asunto es que cualquier tipo que admita un método llamado GetEnumerator () puede ser evaluado por la construcción foreach. Para ilustrar, ¡sígueme!

Supongamos que tenemos una clase de garaje:

// Garage contains a set of Car objects.
public class Garage
{
   private Car[] carArray = new Car[4];
   // Fill with some Car objects upon startup.
   public Garage()
   {
      carArray[0] = new Car("Rusty", 30);
      carArray[1] = new Car("Clunker", 55);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
}

Idealmente, sería conveniente iterar sobre los subelementos del objeto Garage utilizando la construcción foreach, al igual que una matriz de valores de datos:

// This seems reasonable ...
public class Program
{
   static void Main(string[] args)
   {
      Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");
      Garage carLot = new Garage();
      // Hand over each car in the collection?
      foreach (Car c in carLot)
      {
         Console.WriteLine("{0} is going {1} MPH",
         c.PetName, c.CurrentSpeed);
      }
      Console.ReadLine();
   }
}

Lamentablemente, el compilador le informa que la clase Garage no implementa un método llamado GetEnumerator (). Este método está formalizado por la interfaz IEnumerable, que se encuentra al acecho dentro del espacio de nombres System.Collections. Las clases o estructuras que admiten este comportamiento anuncian que pueden exponer subpuntos contenidos al llamante (en este ejemplo, la palabra clave foreach en sí). Aquí está la definición de esta interfaz estándar .NET:

// This interface informs the caller
// that the object's subitems can be enumerated.
public interface IEnumerable
{
   IEnumerator GetEnumerator();
}

Como puede ver, el método GetEnumerator () devuelve una referencia a otra interfaz llamada System.Collections.IEnumerator. Esta interfaz proporciona la infraestructura para permitir que la persona que llama atraviese los objetos internos contenidos en el contenedor compatible con IEnumerable:

// This interface allows the caller to
// obtain a container's subitems.
public interface IEnumerator
{
   bool MoveNext (); // Advance the internal position of the cursor.
   object Current { get;} // Get the current item (read-only property).
   void Reset (); // Reset the cursor before the first member.
}

Si desea actualizar el tipo de garaje para admitir estas interfaces, puede tomar el camino largo e implementar cada método manualmente. Si bien puede proporcionar versiones personalizadas de GetEnumerator (), MoveNext (), Current y Reset (), existe una forma más sencilla. Como el tipo System.Array (así como muchas otras clases de colección) ya implementa IEnumerable e IEnumerator, simplemente puede delegar la solicitud al System.Array de la siguiente manera:

using System.Collections;
...
public class Garage : IEnumerable
{
   // System.Array already implements IEnumerator!
   private Car[] carArray = new Car[4];
   public Garage()
   {
      carArray[0] = new Car("FeeFee", 200);
      carArray[1] = new Car("Clunker", 90);
      carArray[2] = new Car("Zippy", 30);
      carArray[3] = new Car("Fred", 30);
   }
   public IEnumerator GetEnumerator()
   {
      // Return the array object's IEnumerator.
      return carArray.GetEnumerator();
   }
}

Una vez que haya actualizado su tipo de Garaje, puede usarlo con seguridad dentro de la construcción foreach de C #. Además, dado que el método GetEnumerator () se ha definido públicamente, el usuario del objeto también podría interactuar con el tipo IEnumerator:

// Manually work with IEnumerator.
IEnumerator i = carLot.GetEnumerator();
i.MoveNext();
Car myCar = (Car)i.Current;
Console.WriteLine("{0} is going {1} MPH", myCar.PetName, myCar.CurrentSpeed);

Sin embargo, si prefiere ocultar la funcionalidad de IEnumerable del nivel de objeto, simplemente utilice la implementación explícita de la interfaz:

IEnumerator IEnumerable.GetEnumerator()
{
  // Return the array object's IEnumerator.
  return carArray.GetEnumerator();
}

Al hacerlo, el usuario de objetos casuales no encontrará el método GetEnumerator () de Garage, mientras que la construcción foreach obtendrá la interfaz en segundo plano cuando sea necesario.

Adaptado de Pro C # 5.0 y .NET 4.5 Framework

Dijo Roohullah Allem
fuente
1
Fantástica respuesta, gracias! Sin embargo, tengo una pregunta. En el primer ejemplo, recorre la matriz con foreach, pero luego no puede hacerlo en el segundo ejemplo. ¿Es esto porque la matriz está en una clase o porque contiene objetos?
Caleb Palmquist
Gracias por la gran explicación Mi única pregunta es ¿por qué no simplemente tener un método en Garageeso carArray? De esa manera no tiene que implementarse GetEnumerator, ya que Arrayya lo hace. Por ejemploforeach(Car c in carLot.getCars()) { ... }
Nick Rolando
63

Implementar IEnumerable significa que su clase devuelve un objeto IEnumerator:

public class People : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        // return a PeopleEnumerator
    }
}

La implementación de IEnumerator significa que su clase devuelve los métodos y propiedades para la iteración:

public class PeopleEnumerator : IEnumerator
{
    public void Reset()...

    public bool MoveNext()...

    public object Current...
}

Esa es la diferencia de todos modos.

núcleo
fuente
1
Agradable, esto explica (junto con las otras publicaciones) cómo convertir su clase en una que pueda usar "foreach" para iterar sobre su contenido.
Contango
54

Explicación vía Analogy + Code Tutorial

Primero una explicación sin código, luego la agregaré más tarde.

Digamos que está ejecutando una compañía aérea. Y en cada avión desea saber información sobre los pasajeros que vuelan en el avión. Básicamente quieres poder "atravesar" el avión. En otras palabras, desea poder comenzar en el asiento delantero y luego avanzar hacia la parte trasera del avión, preguntando a los pasajeros cierta información: quiénes son, de dónde son, etc. Un avión solo puede hacer esto , si esto es:

  1. contable y
  2. Si tiene un mostrador.

¿Por qué estos requisitos? Porque eso es lo que requiere la interfaz.

Si se trata de una sobrecarga de información, todo lo que necesita saber es que desea poder hacerle algunas preguntas a cada pasajero del avión, comenzando por el primero y llegando hasta el último.

¿Qué significa contable?

Si una aerolínea es "contable", esto significa que DEBE haber una azafata presente en el avión, cuyo único trabajo es contar, y esta azafata DEBE contar de una manera muy específica:

  1. El mostrador / azafata DEBE comenzar antes que el primer pasajero (en la parte delantera de todos donde demuestren seguridad, cómo ponerse el chaleco salvavidas, etc.).
  2. Él / ella (es decir, la azafata) DEBE "moverse a continuación" por el pasillo hasta el primer asiento.
  3. Luego debe registrar: (i) quién es la persona en el asiento y (ii) su ubicación actual en el pasillo.

Procedimientos de conteo

El capitán de la aerolínea quiere un informe sobre cada pasajero cuando sea investigado o contado. Entonces, después de hablar con la persona en el primer asiento, la azafata / mostrador luego informa al capitán, y cuando se entrega el informe, el mostrador recuerda su posición exacta en el pasillo y continúa contando justo donde se fue. apagado.

De esta manera, el capitán siempre puede tener información sobre la persona actual que está siendo investigada. De esa manera, si descubre que a esta persona le gusta el Manchester City, puede darle a ese pasajero un trato preferencial, etc.

  • El mostrador continúa hasta que llega al final del avión.

Atemos esto con los IEnumerables

  • Un enumerable es solo una colección de pasajeros en un avión. La Ley de Aviación Civil: estas son básicamente las reglas que deben seguir todos los IEnumerables. Cada vez que el asistente de la aerolínea acude al capitán con la información del pasajero, básicamente estamos 'cediendo' el pasajero al capitán. El capitán básicamente puede hacer lo que quiera con el pasajero, excepto reorganizar a los pasajeros en el avión. En este caso, reciben un trato preferencial si siguen a Manchester City (¡uf!)

    foreach (Passenger passenger in Plane)
    // the airline hostess is now at the front of the plane
    // and slowly making her way towards the back
    // when she get to a particular passenger she gets some information
    // about the passenger and then immediately heads to the cabin
    // to let the captain decide what to do with it
    { // <---------- Note the curly bracket that is here.
        // we are now cockpit of the plane with the captain.
        // the captain wants to give the passenger free 
        // champaign if they support manchester city
        if (passenger.supports_mancestercity())
        {
            passenger.getFreeChampaign();
        } else
        {
            // you get nothing! GOOD DAY SIR!
        }
    } //  <---- Note the curly bracket that is here!
          the hostess has delivered the information 
          to the captain and goes to the next person
          on the plane (if she has not reached the 
          end of the plane)
    

Resumen

En otras palabras, algo es contable si tiene un contador . Y el contador debe (básicamente): (i) recordar su lugar ( estado ), (ii) poder moverse a continuación , (iii) y saber acerca de la persona actual con la que está tratando.

Enumerable es solo una palabra elegante para "contable". En otras palabras, un enumerable le permite 'enumerar' (es decir, contar).

BKSpurgeon
fuente
23

IEnumerable implementa GetEnumerator. Cuando se llama, ese método devolverá un IEnumerator que implementa MoveNext, Reset y Current.

Por lo tanto, cuando su clase implementa IEnumerable, está diciendo que puede llamar a un método (GetEnumerator) y obtener un nuevo objeto devuelto (un IEnumerator) que puede usar en un bucle como foreach.

DavGarcia
fuente
18

La implementación de IEnumerable le permite obtener un IEnumerator para una lista.

IEnumerator permite el acceso secuencial de estilo foreach a los elementos de la lista, utilizando la palabra clave de rendimiento.

Antes de la implementación foreach (en Java 1.4, por ejemplo), la forma de iterar una lista era obtener un enumerador de la lista, luego pedirle el "siguiente" elemento de la lista, siempre que el valor devuelto como el siguiente El artículo no es nulo. Foreach simplemente lo hace implícitamente como una característica del lenguaje, de la misma manera que lock () implementa la clase Monitor detrás de escena.

Espero que foreach funcione en listas porque implementan IEnumerable.

Neil Barnwell
fuente
si es para una lista, ¿por qué no puedo usar foreach?
prodev42
.Net duck escribe la instrucción foreach, pero IEnumerable / IEnumerable <T> es la forma adecuada de decir que su clase se puede enumerar.
user7116
15
  • Un objeto que implementa IEnumerable permite que otros visiten cada uno de sus elementos (por un enumerador) .
  • Un objeto que implementa IEnumerator es hacer la iteración. Está girando sobre un objeto enumerable.

Piense en objetos enumerables como listas, pilas, árboles.

Lieven Keersmaekers
fuente
12

IEnumerable e IEnumerator (y sus contrapartes genéricas IEnumerable <T> e IEnumerator <T>) son interfaces base de implementaciones de iterador en colecciones .Net Framework Class Libray .

IEnumerable es la interfaz más común que verías en la mayoría del código. Permite el bucle foreach, los generadores (piense en el rendimiento ) y, debido a su pequeña interfaz, se usa para crear abstracciones estrechas. IEnumerable depende de IEnumerator .

IEnumerator , por otro lado, proporciona una interfaz de iteración de nivel ligeramente inferior. Se conoce como el iterador explícito que le da al programador más control sobre el ciclo de iteración.

IEnumerable

IEnumerable es una interfaz estándar que permite iterar sobre colecciones que lo admiten (de hecho, todos los tipos de colecciones que se me ocurren hoy implementan IEnumerable ). El soporte del compilador permite funciones de lenguaje como foreach. En términos generales, habilita esta implementación implícita de iterador .

foreach Loop

foreach (var value in list)
  Console.WriteLine(value);

Creo que el foreachbucle es una de las principales razones para usar las interfaces IEnumerable . foreachtiene una sintaxis muy sucinta y muy fácil de entender en comparación con el estilo clásico de C para bucles en los que necesita verificar las diversas variables para ver qué estaba haciendo.

palabra clave de rendimiento

Probablemente una característica menos conocida es que IEnumerable también habilita generadores en C # con el uso de yield returny yield breakdeclaraciones.

IEnumerable<Thing> GetThings() {
   if (isNotReady) yield break;
   while (thereIsMore)
     yield return GetOneMoreThing();
}

Abstracciones

Otro escenario común en la práctica es usar IEnumerable para proporcionar abstracciones minimalistas. Debido a que es una interfaz minúscula y de solo lectura, se le recomienda exponer sus colecciones como IEnumerable (en lugar de List, por ejemplo). De esa manera, puede cambiar su implementación sin romper el código de su cliente (cambie la Lista a una LinkedList, por ejemplo).

Gotcha

Un comportamiento a tener en cuenta es que en las implementaciones de transmisión (por ejemplo, recuperar datos fila por fila de una base de datos, en lugar de cargar todos los resultados en la memoria primero) no puede iterar sobre la colección más de una vez. Esto contrasta con las colecciones en memoria como List , donde puede iterar varias veces sin problemas. ReSharper, por ejemplo, tiene una inspección de código para la posible enumeración múltiple de IEnumerable .

IEnumerator

IEnumerator, por otro lado, es la interfaz detrás de escena que hace que IEnumerble-foreach-magic funcione. Estrictamente hablando, habilita iteradores explícitos.

var iter = list.GetEnumerator();
while (iter.MoveNext())
    Console.WriteLine(iter.Current);

En mi experiencia, IEnumerator rara vez se usa en escenarios comunes debido a su sintaxis más detallada y semántica ligeramente confusa (al menos para mí; por ejemplo, MoveNext () también devuelve un valor, que el nombre no sugiere en absoluto).

Caso de uso para IEnumerator

Solo utilicé IEnumerator en bibliotecas y marcos particulares (nivel ligeramente inferior) donde proporcionaba interfaces IEnumerable . Un ejemplo es una biblioteca de procesamiento de flujo de datos que proporcionó una serie de objetos en un foreachbucle, aunque los datos detrás de escena se recopilaron utilizando varios flujos de archivos y serializaciones.

Codigo del cliente

foreach(var item in feed.GetItems())
    Console.WriteLine(item);

Biblioteca

IEnumerable GetItems() {
    return new FeedIterator(_fileNames)
}

class FeedIterator: IEnumerable {
    IEnumerator GetEnumerator() {
        return new FeedExplicitIterator(_stream);
    }
}

class FeedExplicitIterator: IEnumerator {
    DataItem _current;

    bool MoveNext() {
        _current = ReadMoreFromStream();
        return _current != null;           
    }

    DataItem Current() {
        return _current;   
    }
}
ziya
fuente
9

La implementación IEnumerableesencialmente significa que el objeto puede ser iterado. Esto no significa necesariamente que sea una matriz, ya que hay ciertas listas que no se pueden indexar, pero puede enumerarlas.

IEnumeratores el objeto real utilizado para realizar las iteraciones. Controla el movimiento de un objeto al siguiente en la lista.

La mayoría de las veces, IEnumerable& IEnumeratorse utilizan de forma transparente como parte de un foreachbucle.

Dan Herbert
fuente
6

Diferencias entre IEnumerable e IEnumerator:

  • IEnumerable usa IEnumerator internamente.
  • IEnumerable no sabe qué elemento / objeto se está ejecutando.
  • Cada vez que pasamos IEnumerator a otra función, conoce la posición actual del elemento / objeto.
  • Cada vez que pasamos una colección IEnumerable a otra función, no conoce la posición actual del elemento / objeto (no sabe qué elemento está ejecutando)

    IEnumerable tiene un método GetEnumerator ()

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

IEnumerator tiene una propiedad llamada Current y dos métodos, Reset () y MoveNext () (que es útil para conocer la posición actual de un elemento en una lista).

public interface IEnumerator
{
     object Current { get; }
     bool MoveNext();
     void Reset();
}
Ajay
fuente
5

IEnumerable es un cuadro que contiene Ienumerator. IEnumerable es la interfaz base para todas las colecciones. foreach loop puede funcionar si la colección implementa IEnumerable. En el siguiente código, explica el paso de tener nuestro propio enumerador. Primero definamos nuestra clase de la cual vamos a hacer la colección.

public class Customer
{
    public String Name { get; set; }
    public String City { get; set; }
    public long Mobile { get; set; }
    public double Amount { get; set; }
}

Ahora definiremos la Clase que actuará como una colección para nuestra clase Cliente. Tenga en cuenta que está implementando la interfaz IEnumerable. Para que tengamos que implementar el método GetEnumerator. Esto devolverá nuestro enumerador personalizado.

public class CustomerList : IEnumerable
{
    Customer[] customers = new Customer[4];
    public CustomerList()
    {
        customers[0] = new Customer { Name = "Bijay Thapa", City = "LA", Mobile = 9841639665, Amount = 89.45 };
        customers[1] = new Customer { Name = "Jack", City = "NYC", Mobile = 9175869002, Amount = 426.00 };
        customers[2] = new Customer { Name = "Anil min", City = "Kathmandu", Mobile = 9173694005, Amount = 5896.20 };
        customers[3] = new Customer { Name = "Jim sin", City = "Delhi", Mobile = 64214556002, Amount = 596.20 };
    }

    public int Count()
    {
        return customers.Count();
    }
    public Customer this[int index]
    {
        get
        {
            return customers[index];
        }
    }
    public IEnumerator GetEnumerator()
    {
        return customers.GetEnumerator(); // we can do this but we are going to make our own Enumerator
        return new CustomerEnumerator(this);
    }
}

Ahora vamos a crear nuestro propio enumerador personalizado de la siguiente manera. Entonces, tenemos que implementar el método MoveNext.

 public class CustomerEnumerator : IEnumerator
    {
        CustomerList coll;
        Customer CurrentCustomer;
        int currentIndex;
        public CustomerEnumerator(CustomerList customerList)
        {
            coll = customerList;
            currentIndex = -1;
        }

        public object Current => CurrentCustomer;

        public bool MoveNext()
        {
            if ((currentIndex++) >= coll.Count() - 1)
                return false;
            else
                CurrentCustomer = coll[currentIndex];
            return true;
        }

        public void Reset()
        {
            // we dont have to implement this method.
        }
    }

Ahora podemos usar foreach loop sobre nuestra colección como a continuación;

    class EnumeratorExample
    {
        static void Main(String[] args)
        {

            CustomerList custList = new CustomerList();
            foreach (Customer cust in custList)
            {
                Console.WriteLine("Customer Name:"+cust.Name + " City Name:" + cust.City + " Mobile Number:" + cust.Amount);
            }
            Console.Read();

        }
    }
Amir
fuente
4

Una comprensión del patrón Iterator será útil para usted. Recomiendo leer lo mismo.

Patrón de iterador

En un nivel alto, el patrón iterador puede usarse para proporcionar una forma estándar de iterar a través de colecciones de cualquier tipo. Tenemos 3 participantes en el patrón iterador, la colección real (cliente), el agregador y el iterador. El agregado es una clase de interfaz / resumen que tiene un método que devuelve un iterador. Iterator es una interfaz / clase abstracta que tiene métodos que nos permiten iterar a través de una colección.

Para implementar el patrón, primero debemos implementar un iterador para producir un concreto que pueda iterar sobre la colección (cliente) en cuestión. Luego, la colección (cliente) implementa el agregador para devolver una instancia del iterador anterior.

Aquí está el diagrama UML Patrón de iterador

Básicamente, en C #, IEnumerable es el agregado abstracto e IEnumerator es el Iterador abstracto. IEnumerable tiene un método único GetEnumerator que se encarga de crear una instancia de IEnumerator del tipo deseado. Colecciones como Listas implementan el IEnumerable.

Ejemplo. Supongamos que tenemos un método getPermutations(inputString)que devuelve todas las permutaciones de una cadena y que el método devuelve una instancia deIEnumerable<string>

Para contar el número de permutaciones podríamos hacer algo como lo siguiente.

 int count = 0;
        var permutations = perm.getPermutations(inputString);
        foreach (string permutation in permutations)
        {
            count++;
        }

El compilador de c # convierte más o menos lo anterior a

using (var permutationIterator = perm.getPermutations(input).GetEnumerator())
        {
            while (permutationIterator.MoveNext())
            {
                count++;
            }
        }

Si tiene alguna pregunta, no dude en preguntar.

lalatnayak
fuente
2

Una contribución menor.

Como muchos de ellos explican sobre 'cuándo usar' y 'usar con foreach'. Pensé en agregar Otra diferencia de estados aquí, según lo solicitado en la pregunta sobre la diferencia entre IEnumerable y IEnumerator.

Creé el siguiente código de muestra basado en los hilos de discusión a continuación.

IEnumerable, IEnumerator vs foreach, cuándo usar qué ¿Cuál es la diferencia entre IEnumerator e IEnumerable?

Enumerator conserva el estado (posición de iteración) entre las llamadas a funciones, mientras que las iteraciones, por otro lado, Enumerable no lo hace.

Aquí está el ejemplo probado con comentarios para entender.

Expertos por favor agreguen / corríjanme.

static void EnumerableVsEnumeratorStateTest()
{
    IList<int> numList = new List<int>();

    numList.Add(1);
    numList.Add(2);
    numList.Add(3);
    numList.Add(4);
    numList.Add(5);
    numList.Add(6);

    Console.WriteLine("Using Enumerator - Remembers the state");
    IterateFrom1to3(numList.GetEnumerator());

    Console.WriteLine("Using Enumerable - Does not Remembers the state");
    IterateFrom1to3Eb(numList);

    Console.WriteLine("Using Enumerable - 2nd functions start from the item 1 in the collection");
}

static void IterateFrom1to3(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());

        if (numColl.Current > 3)
        {
            // This method called 3 times for 3 items (4,5,6) in the collection. 
            // It remembers the state and displays the continued values.
            IterateFrom3to6(numColl);
        }
    }
}

static void IterateFrom3to6(IEnumerator<int> numColl)
{
    while (numColl.MoveNext())
    {
        Console.WriteLine(numColl.Current.ToString());
    }
}

static void IterateFrom1to3Eb(IEnumerable<int> numColl)
{
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());

        if (num>= 5)
        {
            // The below method invokes for the last 2 items.
            //Since it doesnot persists the state it will displays entire collection 2 times.
            IterateFrom3to6Eb(numColl);
        }
    }
}

static void IterateFrom3to6Eb(IEnumerable<int> numColl)
{
    Console.WriteLine();
    foreach (int num in numColl)
    {
        Console.WriteLine(num.ToString());
    }
}
Sai
fuente
2

He notado estas diferencias:

R. Repetimos la lista de manera diferente, foreach se puede usar para IEnumerable y while loop para IEnumerator.

B. IEnumerator puede recordar el índice actual cuando pasamos de un método a otro (comienza a funcionar con el índice actual) pero IEnumerable no puede recordar el índice y restablece el índice al principio. Más en este video https://www.youtube.com/watch?v=jd3yUjGc9M0

Rueda giratoria
fuente
1

IEnumerabley IEnumeratorambos son interfaces en C #.

IEnumerablees una interfaz que define un método único GetEnumerator()que devuelve una IEnumeratorinterfaz.

Esto funciona para el acceso de solo lectura a una colección que implementa que IEnumerablese puede usar con una foreachinstrucción.

IEnumeratortiene dos métodos, MoveNexty Reset. También tiene una propiedad llamada Current.

A continuación se muestra la implementación de IEnumerable e IEnumerator.

Jihed Jaoidi
fuente
0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Enudemo
{

    class Person
    {
        string name = "";
        int roll;

        public Person(string name, int roll)
        {
            this.name = name;
            this.roll = roll;
        }

        public override string ToString()
        {
            return string.Format("Name : " + name + "\t Roll : " + roll);
        }

    }


    class Demo : IEnumerable
    {
        ArrayList list1 = new ArrayList();

        public Demo()
        {
            list1.Add(new Person("Shahriar", 332));
            list1.Add(new Person("Sujon", 333));
            list1.Add(new Person("Sumona", 334));
            list1.Add(new Person("Shakil", 335));
            list1.Add(new Person("Shruti", 336));
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
           return list1.GetEnumerator();
        }
    }



    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();  // Notice here. it is simple object but for 
                                //IEnumerator you can get the collection data

            foreach (Person X in d)
            {
                Console.WriteLine(X);
            }

            Console.ReadKey();
        }
    }
}
/*
Output : 

Name : Shahriar  Roll : 332
Name : Sujon     Roll : 333
Name : Sumona    Roll : 334
Name : Shakil    Roll : 335
Name : Shruti    Roll : 336
  */
MD Shahriar
fuente