2010-12-28 13 views
7

Utilizo el siguiente código para permitir que myClass use foreach. Pero soy bastante nuevo en la programación y tengo algunas dificultades para comprender el siguiente código. Describí mis problemas en los comentarios. Estaría agradecido por proporcionar cierta información.Pregunta sobre IEnumerable e IEnumerator

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 
+3

Dejaré que john skeet responda esto –

+4

@Hasan: Temo lo que él te hará al escribir mal su nombre. – JYelton

Respuesta

11

¿Cuál es la diferencia entre IEnumerator e IEnumerable?

La respuesta de Jason es buena, pero pensé que solo agregaría cómo pienso sobre esto. Imagine que tiene una secuencia:

1, 1, 2, 3, 5, 8, 13, ... 

Ahora imagine 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. Primero, puede darle lo que está apuntando. En segundo lugar, puede señalarse a sí mismo en lo siguiente.

IEnumerator es una flecha. Tiene una propiedad, Actual, que le proporciona aquello a lo que apunta. Tiene un método, MoveNext() que hace que apunte a lo siguiente.

¿Cómo se obtiene una flecha en primer lugar? Necesitas una fábrica de flechas Le pides a la fábrica una flecha, y te da una flecha que apunta al primer elemento de la secuencia.

IEnumerable es una fábrica de flechas. Tiene un método, GetEnumerator, que le da una flecha al primer elemento de la secuencia.

Una propiedad agradable de este esquema es que puede tener varias flechas apuntando a diferentes lugares en la misma secuencia.

¿Cuáles son los beneficios de implementar la interfaz genérica IEnumerable en lugar de solo IEnumerable?

Supongamos que la secuencia es de números enteros. Si implementa IEnumerable entonces cuando se dice

foreach(int x in mysequence) 

lo que realmente va a hacer es convertir el int en la secuencia de oponerse, boxeo del número entero, y luego unbox inmediatamente el objeto de nuevo al número entero, añadiendo una asignación de memoria completamente innecesario a cada operación individual. Si el compilador sabe que la secuencia es de números enteros, 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 lo hace, entonces usted tiene que decir

string first = (string)mysequence.First(); 

que es innecesario y propenso a errores. En lugar de indicarle al compilador a través de un molde que el tipo es una cadena, simplemente puede garantizar que el tipo es cadena utilizando el sistema de tipo.

+2

Buena metáfora con el concepto de flecha. También puede valer la pena mencionar que un efecto secundario común de este modelo es que alterar la colección que comienza enumerada generalmente invalida todas las "flechas" que apuntan hacia él. – LBushkin

+0

Nota secundaria sobre _ "GetEnumerator, que le da una flecha al primer elemento de la secuencia" _: Según [MSDN] (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable .getenumerator (v = vs.110) .aspx), le da una flecha que apunta a algo indefinido _antes de_ lo primero. – jan

+0

@jan: ¡Buen punto! –

0

GetEnumerator ha existido desde antes de los genéricos se introdujeron a la lengua, a fin de no romper el código preexistente, el método predeterminado llama a través de la implementación genérica.

Con una enumeración genérica, el consumidor de su clase no necesita convertir cada elemento en una cadena al iterar.

6

1) ¿Qué es IEnumerator para? ¿Cuál es la diferencia entre IEnumerator y IEnumerable?

IEnumerator es una interfaz que representa métodos que le permiten enumerar una secuencia. La diferencia entre IEnumerator y IEnumerable es que la primera representa el contrato para objetos que le permiten enumerar una secuencia, y la última representa el contrato para objetos que son una secuencia que puede enumerarse.

public IEnumerator<string> GetEnumerator() { 
     yield return "first";   
     yield return "second";  
}  


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

2) ¿Cuál es? Simplemente llama al método anterior.

El primero representa una implementación del método GetEnumerator en el contrato IEnumerable<string>. Este último representa una implementación explícita del método GetEnumerator en el contrato IEnumerable. El problema es que ambos contratos tienen un método llamado GetEnumerator pero con diferentes tipos de devolución para que un método no pueda satisfacer simultáneamente ambos contratos (cualquier clase que implemente IEnumerable<T> también debe implementar IEnumerable como IEnumerable<T> : IEnumerable). Este último invoca la implementación de IEnumerable<string>.GetEnumerator ya que es una implementación sensata que devuelve IEnumerator como IEnumerator<string> : IEnumerator.

3) Por último, ¿qué ventajas tengo al implementar la interfaz genérica IEnumerable<string> en lugar de solo IEnumerable?

Strong typing. Usted sabe que los elementos en una secuencia IEnumerable<string> son todas instancias de String mientras que usted no sabe que para IEnumerable y podría terminar tratando de transmitir un elemento de este último a una instancia de String cuando no puede ser.

3

1) ¿Para qué sirve IEnumerator?

IEnumerator es la parte que realmente funciona con los miembros MoveNext() y Current.

¿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] ¿Para qué sirve? Simplemente llama al método anterior

El método no genérico está ahí para la compatibilidad con versiones anteriores. Tenga en cuenta que se mueve 'fuera de la vista' tanto como sea posible mediante el uso de la implementación explícita. Implementarlo porque debe y luego olvidarse de él.

3) Por último ¿qué beneficios tengo de la implementación de la interfaz IEnumerable genética en lugar de sólo IEnumerable

Cuando se utiliza con el foreach 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(); 
3

Esta es la declaración de IEnumerable<T>:

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

no tienes elección, que tienen para implementar el IE no genérico interfaz numerable también. Obtendrá un error de compilación si omite la implementación IEnumerable.GetEnumerator(). Este es el equipaje sobrante de los días de .NET 1.x donde los genéricos no estaban disponibles todavía y el período de transición para .NET 2.0 donde necesitaba soportar la interoperabilidad con los ensamblados de .NET 1.x. Estamos atrapados con eso.