¿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?
c#
ienumerable
ienumerator
prodev42
fuente
fuente
Respuestas:
No utilizas
IEnumerable
"over"foreach
. La implementaciónIEnumerable
haceforeach
posible el uso .Cuando escribes código como:
es funcionalmente equivalente a escribir:
Por "funcionalmente equivalente", quiero decir que en realidad es en eso que el compilador convierte el código. No se puede utilizar
foreach
enbaz
este ejemplo a menosbaz
implementosIEnumerable
.IEnumerable
significa quebaz
implementa el métodoEl
IEnumerator
objeto que devuelve este método debe implementar los métodos.y
El primer método avanza al siguiente objeto en el
IEnumerable
objeto que creó el enumerador, devolviendofalse
si 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 implementaIEnumerable
, puede hacer que su clase sea utilizable enforeach
declaraciones mediante la implementaciónIEnumerable
(y creando una clase de enumerador queGetEnumerator
devolverá su nuevo método).fuente
bool MoveNext()
método y unaCurrent
propiedad 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.iterator
?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:
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:
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:
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:
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:
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:
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:
Sin embargo, si prefiere ocultar la funcionalidad de IEnumerable del nivel de objeto, simplemente utilice la implementación explícita de la interfaz:
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
fuente
Garage
esocarArray
? De esa manera no tiene que implementarseGetEnumerator
, ya queArray
ya lo hace. Por ejemploforeach(Car c in carLot.getCars()) { ... }
Implementar IEnumerable significa que su clase devuelve un objeto IEnumerator:
La implementación de IEnumerator significa que su clase devuelve los métodos y propiedades para la iteración:
Esa es la diferencia de todos modos.
fuente
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:
¿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:
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.
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!)
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).
fuente
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.
fuente
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.
fuente
Piense en objetos enumerables como listas, pilas, árboles.
fuente
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
Creo que el
foreach
bucle es una de las principales razones para usar las interfaces IEnumerable .foreach
tiene 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 return
yyield break
declaraciones.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.
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
foreach
bucle, aunque los datos detrás de escena se recopilaron utilizando varios flujos de archivos y serializaciones.Codigo del cliente
Biblioteca
fuente
La implementación
IEnumerable
esencialmente 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.IEnumerator
es 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
&IEnumerator
se utilizan de forma transparente como parte de unforeach
bucle.fuente
Diferencias entre IEnumerable e IEnumerator:
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 ()
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).
fuente
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.
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.
Ahora vamos a crear nuestro propio enumerador personalizado de la siguiente manera. Entonces, tenemos que implementar el método MoveNext.
Ahora podemos usar foreach loop sobre nuestra colección como a continuación;
fuente
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
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.
El compilador de c # convierte más o menos lo anterior a
Si tiene alguna pregunta, no dude en preguntar.
fuente
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.
fuente
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
fuente
IEnumerable
yIEnumerator
ambos son interfaces en C #.IEnumerable
es una interfaz que define un método únicoGetEnumerator()
que devuelve unaIEnumerator
interfaz.Esto funciona para el acceso de solo lectura a una colección que implementa que
IEnumerable
se puede usar con unaforeach
instrucción.IEnumerator
tiene dos métodos,MoveNext
yReset
. También tiene una propiedad llamadaCurrent
.A continuación se muestra la implementación de IEnumerable e IEnumerator.
fuente
fuente