2011-02-11 20 views
37

¿Cuál es la diferencia entre IEnumerable y IEnumerable<T>?Diferencia entre IEnumerable e IEnumerable <T>?

He visto muchas clases de framework implementando ambas interfaces, por lo tanto, me gustaría saber qué ventajas se obtienen al implementar ambas.

favor, eche un vistazo cómo han sido definidos:

public interface IEnumerable 
{ 
    [DispId(-4)] 
    IEnumerator GetEnumerator(); 
} 
public interface IEnumerable<T> : IEnumerable 
{ 
    IEnumerator<T> GetEnumerator(); 
} 

Como vemos, IEnumerable<T> deriva de IEnumerable, eso significa que lo tiene IEnumerable, IEnumerable<T> hereda, entonces ¿por qué ponemos en práctica tanto en lugar de sólo IEnumerable<T> ? ¿Implementar IEnumerable<T> no es suficiente?

mismo modo, hay otros pares similares:

  • IList y IList<T>
  • ICollection y ICollection<T>

me gustaría saber acerca de estos también.

Respuesta

48

Básicamente las interfaces no genéricas fueron lo primero, en .NET 1.0 y 1.1. Luego, cuando salió .NET 2.0, salieron los equivalentes genéricos. La vida habría sido mucho más fácil si los genéricos habían hecho en .NET 1.0 :)

En cuanto a la implementación "sólo" IEnumerable<T> en lugar de tanto - que, básicamente, tienen para implementar tanto, y usted tiene que utilizar el interfaz explícita implementación también, dado que ambos definen un método sin parámetros GetEnumerator. Como IEnumerator<T> extiende IEnumerator también, que es normalmente algo como esto:

public IEnumerator<T> GetEnumerator() 
{ 
    // Return real iterator 
} 

// Explicit implementation of nongeneric interface 
IEnumerator IEnumerable.GetEnumerator() 
{ 
    // Delegate to the generic implementation 
    return GetEnumerator(); 
} 

Por otro lado, con los bloques de iterador introducidas en C# 2 (con yield return etc) que rara vez se necesita para poner en práctica estas cosas totalmente a mano, por suerte. Es posible que deba escribir algo como el anterior, y luego use yield return en el método GetEnumerator.

Tenga en cuenta que hace IList<T> no se extienden IList y ICollection<T> hace no se extienden ICollection. Eso es porque es menos seguro para los tipos ... mientras que cualquier iterador genérico se puede ver como un iterador no genérico debido a la conversión (potencialmente de boxeo) de cualquier valor a object, y ICollection permiten que los valores sean añadidos al colección; y no tiene sentido agregar (decir) una cadena a IList<int>.

EDITAR: La razón por la que necesitamos IEnumerable<T> es para que podamos iterar de forma segura y propagar esa información. Si le devuelvo un IEnumerable<string>, sabe que puede asumir con seguridad que todo lo devuelto será una referencia de cadena o nulo. Con IEnumerable, tuvimos que emitir efectivamente (a menudo implícitamente en una declaración foreach) cada elemento que se devolvió de la secuencia, porque la propiedad Current de IEnumerator es solo del tipo object.En cuanto a por qué todavía necesita IEnumerable - porque las interfaces antiguas nunca desaparecen, básicamente. Hay demasiado código existente usándolo.

Habría sido posible para no extender IEnumerable<T>IEnumerable, pero entonces cualquier código que desee hacer uso de una IEnumerable<T> no podía poner en un método de aceptar IEnumerable - y había una gran cantidad de métodos como el que a partir de .NET 1.1 y 1.0.

+12

1 vida habría sido mucho más fácil si los genéricos se había hecho en .NET 1.0 ... – Oded

+0

@ Jon: la pregunta es: ¿por qué necesitamos para implementar 'IEnumerable' cuando ya implementar' 'IEnumerable , ¿o viceversa? – Nawaz

+0

@Nawaz: he editado mi respuesta. ¿Qué tan cómodo está con la idea de por qué los genéricos son algo bueno? –

5

Uno vuelve un objeto de tipo de objeto, el otro vuelve un objeto de tipo T.

2

cuanto a por qué se ve clases que definen tanto, suficiente, sin embargo IEnumerable < T> implementa IEnumerable, no es necesario, pero es es agradable en una autoedición para enumerar las interfaces secundarias a veces. Considere

interface IA { } 
interface IB : IA { } 

class A : IB {} // legal, IB implements IA 

class B : IA, IB {} // also legal, possible more clear on intent 
1

Al iterar a través del bucle, IEnumerator mantiene el estado. Recuerda la posición del cursor y IEnumerable no.

Cuestiones relacionadas