Cuestión relativa a IEnumerable y IEnumerator
-
13-10-2019 - |
Pregunta
Yo uso el siguiente código para permitir myClass usar foreach. Pero soy bastante nuevo en la programación y tener alguna dificultad para comprender el siguiente código. Describí mis problemas en los comentarios. Le agradecería para proporcionar alguna información.
public class MyClass : IEnumerable<string>
{
//1) What is IEnumerator for?
// Whats the difference between IEnumerator and IEnumerable
public IEnumerator<string> GetEnumerator()
{
yield return "first";
yield return "second";
}
//2) What is it for? It just calls above method
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
//3) Lastly what benefits I have from implementing genetic interface
//IEnumerable<string> instead of just IEnumerable
Solución
¿Cuál es la diferencia entre IEnumerator y IEnumerable?
La respuesta de Jason es bueno, pero pensé que acababa de añadir a lo que pienso acerca de esto. Imagine que tiene una secuencia:
1, 1, 2, 3, 5, 8, 13, ...
Ahora imagina que tiene una flecha que apunta en alguna posición de esa secuencia:
1, 1, 2, 3, 5, 8, 13, ...
^
Una "flecha" es un objeto que puede hacer dos cosas. En primer lugar, se le puede dar lo que está apuntando. En segundo lugar, puede hacer que en sí apuntan a la siguiente cosa.
IEnumerator es una flecha. Tiene una propiedad, actual, que le da lo que está apuntando. Tiene un método, MoveNext () que se hace punto en la parte siguiente cosa.
¿Cómo se obtiene una flecha en el primer lugar? Es necesario una fábrica de flecha. Usted pregunta a la fábrica para una flecha, y le da una flecha que apunta al primer elemento de la secuencia.
IEnumerable es una fábrica de flecha. Tiene un método, GetEnumerator, que le da una flecha al primer elemento de la secuencia.
Una bonita característica de este esquema es que se pueden tener varias flechas que apuntan a diferentes lugares en la misma secuencia.
¿cuáles son los beneficios de implementar IEnumerable interfaz genérica en lugar de sólo IEnumerable?
Supongamos que la secuencia es de enteros. Si implementa IEnumerable
entonces cuando se dice
foreach(int x in mysequence)
lo que realmente hacer es convertir el int en la secuencia de objeto, el boxeo el número entero y, a continuación Unbox inmediatamente la parte posterior objeto a número entero, añadiendo una asignación de memoria completamente innecesario a cada operación individual. Si el compilador sabe que la secuencia de números enteros es entonces se puede omitir la operación de boxeo innecesaria.
Supongamos que la secuencia es de cadenas. Si implementa IEnumerable<string>
entonces se puede decir:
string first = mysequence.First();
Si no, entonces usted tiene que decir
string first = (string)mysequence.First();
que es innecesario y propenso a errores. En lugar de instruir al compilador a través de un reparto en el que el tipo es una cadena, puede simplemente Garantía que el tipo es cadena utilizando el sistema de tipos.
Otros consejos
1) ¿Qué es para
IEnumerator
? ¿Cuál es la diferencia entreIEnumerator
yIEnumerable
?
IEnumerator
es una interfaz que representa métodos que permiten enumerar una secuencia. La diferencia entre IEnumerator
y IEnumerable
es que el primero representa el contrato para los objetos que le permiten enumerar una secuencia, y el segundo representa el contrato para objetos que son una secuencia que se pueden enumerar de nuevo.
public IEnumerator<string> GetEnumerator() {
yield return "first";
yield return "second";
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
2) ¿Qué es? Simplemente llama método anterior.
La primera representa una implementación del método en la GetEnumerator
IEnumerable<string>
contrato. Esta última representa una implementación explícita de la GetEnumerator
método en la IEnumerable
contrato. La cuestión es que tanto los contratos tienen un método llamado GetEnumerator
pero con diferentes tipos de retorno de manera que un método no puede satisfacer simultáneamente los dos contratos (cualquier IEnumerable<T>
implementación de clase también debe implementar IEnumerable
como IEnumerable<T> : IEnumerable
). Este último invoca la ejecución de IEnumerable<string>.GetEnumerator
ya que es una aplicación sensata que devuelve un IEnumerator
como IEnumerator<string> : IEnumerator
.
3) Por último qué ventajas tengo de la aplicación de
IEnumerable<string>
interfaz genérica en lugar de sóloIEnumerable
?
La tipificación estricta. Usted sabe que los elementos de una secuencia de IEnumerable<string>
son todas las instancias de String
mientras que usted no sabe que para IEnumerable
y podría terminar tratando de echar un elemento de este último a una instancia de String
cuando no puede ser.
Esta es la declaración de IEnumerable<T>
:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
No tienes elección, que Tienes para implementar la interfaz IEnumerable no genérico también. Usted obtendrá un error de compilación si se omite la aplicación IEnumerable.GetEnumerator (). Esto es equipaje sobrante de los días 1.x .NET donde genéricos no estaban disponibles todavía y el período de transición para .NET 2.0 donde se necesita para apoyar interoperabilidad con .NET 1.x ensamblajes. Estamos atrapados con él.
1) ¿Cuál es IEnumerator para?
IEnumerator es la parte real de trabajo con el MoveNext () y los miembros actuales.
¿Cuál es la diferencia entre IEnumerator y IEnumerable
IEnumerable es la interfaz para una colección a la señal que tiene una GetEnumerator ().
2) [GetEnumerator no genérico] ¿Qué es para? Simplemente llama método anterior
El método no genérico es allí sólo para la compatibilidad hacia atrás. Tenga en cuenta que se mueve 'a la vista' tanto como sea posible mediante el uso de la aplicación explícita. Ponerlo en práctica, ya que debe y luego olvidarse de él.
3) Por último qué ventajas tengo de la implementación de la interfaz genética IEnumerable en lugar de sólo IEnumerable
Cuando se utiliza con foreach
la adavantage es pequeño, como foreach escribirá fundido a la variable de bucle. Se le permitirá utilizar var
en el foreach:
foreach (var s in myClassInstance) // needs `IEnumerable<string>`
foreach (string s in myClassInstance) // works with `IEnumerable` as well
Pero con IEnumerable<string>
también tiene una interfaz de tipo seguro a otras áreas, sobre todo LINQ:
MyClass mc = new MyClass ();
string s = mc.FirstOrDefault();
GetEnumerator
ha existido desde antes de los genéricos se introdujeron a la lengua, a fin de no romper el código pre-existente, las llamadas al método por defecto a través de la implementación genérica.
Con una enumeración genérica, el consumidor de la clase no tiene que emitir cada elemento de cadena cuando la iteración.
En cuanto a la tercera pregunta aquí están algunas respuestas (¿Por qué los genéricos de uso?):
debemos usar colección genérica para mejorar la seguridad y la rendimiento?
En resumen, utilizar colecciones genéricas cada vez que puede.