Diferencia entre varias interfaces genéricas de colección en C #

11

He estado jugando con C # para Windows y el desarrollo de ASP.net MVC desde hace algún tiempo. Pero todavía no estoy claro en algunas áreas. Estoy tratando de entender la diferencia básica y los problemas de rendimiento con el uso e intercambio de tipos similares de interfaces de colección genéricas .

¿Cuál es la diferencia básica entre IEnumerable<T>, ICollection<T>, List<T>(Class)?

Parece que los uso e intercambio sin ver ningún problema en mis aplicaciones. Además, ¿hay más colecciones genéricas similares como estas que puedan intercambiarse con esas tres?

Pankaj Upadhyay
fuente
2
también hay IList <T> también
jk.

Respuestas:

19

List <T> es una clase e implementa las interfaces ICollection <T> e IEnumerable <T> . Además, ICollection <T> extiende la interfaz IEnumerable <T>. No son intercambiables, al menos no desde todos los puntos de vista.

Si tiene una Lista <T>, tiene la garantía de que este objeto implementa métodos y propiedades que la interfaz ICollection <T> y IEnumerable <T> deben implementar. El compilador lo sabe y se le permite convertirlos "abajo" a una ICollection <T> o IEnumerable <T> implícitamente. Sin embargo, si tiene una ICollection <T>, primero debe verificar explícitamente en su código si es una Lista <T> o alguna otra cosa, tal vez un Diccionario <T> (donde T es un KeyValuePair ) antes de convertirlo en lo que deseo.

Usted sabe que ICollection extiende IEnumerable, por lo que puede convertirlo en IEnumerable. Pero si solo tiene un IEnumerable, nuevamente no se le garantiza que sea una Lista. Puede ser, pero podría ser otra cosa. Debería esperar una excepción de conversión no válida si intenta emitir una Lista <T> a un Diccionario <T>, por ejemplo.

Por lo tanto, no son "intercambiables".

Además, hay muchas interfaces genéricas, consulte lo que puede encontrar en el espacio de nombres System.Collections.Generic .

Editar: con respecto a su comentario, no hay absolutamente ninguna penalización de rendimiento si usa List <T> o una de las interfaces que implementa. Aún necesitará crear un nuevo objeto, consulte el siguiente código:

List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;

list , myColl y myEnum apuntan al mismo objeto. Ya sea que lo declare como una Lista o una ICollection o un IEnumerable, todavía necesito que el programa cree una Lista. Podría haber escrito esto:

ICollection<T> myColl = new List<T>();

myColl , en tiempo de ejecución sigue siendo una lista.

Sin embargo , este es el punto más importante ... para reducir el acoplamiento y aumentar la capacidad de mantenimiento , siempre debe declarar sus variables y parámetros de método utilizando el mínimo denominador posible para usted, ya sea una interfaz o una clase abstracta o concreta.

Imagine que lo único que necesita el método "PerformOperation" es enumerar elementos, hacer un trabajo y salir, en ese caso no necesita los cien métodos más disponibles en la Lista <T>, solo necesita lo que está disponible en IEnumerable <T >, por lo que debería aplicarse lo siguiente:

public void PerformOperation(IEnumerable<T> myEnumeration) { ... }

Al hacerlo, usted y otros desarrolladores saben que cualquier objeto de una clase que implemente la interfaz IEnumerable <T> se puede asignar a este método. Puede ser una Lista, un Diccionario o una clase de colección personalizada que otro desarrollador haya escrito.

Si, por el contrario, especifica que necesita explícitamente una Lista concreta <T> (y aunque rara vez es el caso en la vida real, aún puede suceder), usted y otros desarrolladores saben que debe ser una Lista u otra clase concreta heredada de la lista.

Jalayn
fuente
Ante todo gracias. Ahora, el punto de preocupación es cómo decidir cuál usar. Como List <T> implementa ambas interfaces, ¿por qué no usarla siempre en todos los lugares donde se requiere IEnumerable o ICollection? ¿Siempre usar la lista tendrá un impacto en el rendimiento? Edite su respuesta para responder a estas inquietudes
Pankaj Upadhyay
Edité para responder a sus preguntas de rendimiento
Jalayn
+1, pero agregaría que en los raros casos en los que realmente necesita pasar una lista a un método, debe usar en IListlugar de Listen la declaración del método.
Konamiman
@Konamiman: depende de si necesita List<>una funcionalidad específica, como .AddRange(). El IList<>no expone eso.
Bobson
6

Eche un vistazo a las páginas de MSDN para ICollection e IEnumerable .

En términos muy abstractos, así es como concibo estos tipos.

Un IEnumerable es cualquier cosa que se pueda enumerar, es decir, iterar. No necesariamente significa una 'colección'; por ejemplo, un IQueryable implementa IEnumerable y no es una colección, pero es algo que se puede consultar para devolver objetos. Para implementar IEnumerable, un objeto solo necesita poder devolver un objeto cuando se lo consulta. Podría decir que tengo una Enumerable de tareas que voy a hacer hoy (no es una lista porque no la he escrito o formulado, pero podría decirte lo que voy a hacer ahora, y si preguntaras 'y luego', podría decirte la siguiente tarea).

Una ICollection es más concreta que una IEnumerable. Una diferencia clave es que una Colección sabe cuántos elementos contiene; para calcular cuántos elementos hay en un Enumerable, puede recorrerlos y contarlos de manera efectiva:

Yo: Chicos, ¿cuántos artículos tienen cada uno en ustedes?

Enumerable: Realmente no lo sé. Bueno, aquí hay un artículo. Tengo otro, así que son dos. Y otro, así que son tres ... y otro ... bueno, así que es 2382. No más artículos, así que tengo 2382. No me preguntes de nuevo porque tendré que revisarlos todos de nuevo.

Colección: Tengo 2382 artículos. Eso ya lo se.

Una colección es típicamente algo que ya sabe dónde están todos sus elementos, y no tendrá que ir a buscarlos o generarlos cuando los solicite. Es más ... concreto que un Enumerable.

En mi opinión, la diferencia entre un Enumerable y una Colección es mucho mayor que la diferencia entre una Colección y una Lista. De hecho, me cuesta pensar en una diferencia práctica entre una Colección y una Lista, pero creo que Lista proporciona mejores métodos para buscar y ordenar.

Otros tipos de colección incluyen Queuey Stack, así como Dictionary.

Los nombres de estos tipos son bastante útiles: puede concebir una cola y una pila como sus contrapartes del mundo real, y considerar las diferencias que podría tener con una Lista.

Kirk Broadhurst
fuente
"Estoy luchando por pensar en una diferencia práctica entre una Colección y una Lista" ... Más adelante en tu respuesta, respondes esto tú mismo. Una Listes una ICollection, pero una ICollectionno siempre es una List( Queue, Stack, Dictionary, ...)
Steven Jeuris
@ Steven Es una respuesta muy divagante. Estoy de acuerdo en que esta es una diferencia importante, pero no la llamaría una diferencia práctica. ¿Qué significa para el usuario?
Kirk Broadhurst, el
¡Eso es fácil! :) Queue<int> queue = (Queue<int>)list;arrojará un InvalidCastExceptioncuando listno es un Queue<int>. La diferencia entre la cola y la lista está fuera del alcance de esta pregunta.
Steven Jeuris el
No es el aspecto crítico de IEnumerable que puede devolver los elementos actuales y los siguientes ; de alguna manera alude a eso, pero no lo dice explícitamente. Esencialmente, algo que implementa IEnumerable solo no puede devolver un elemento arbitrario de sus miembros cuando se le consulta, solo el actual y el siguiente.
cori
@cori Esa es una forma muy sucinta de decirlo, mucho más claro que mi respuesta.
Kirk Broadhurst el
-1

IQueryable:

la consulta no se ejecuta hasta que realmente se repite sobre los elementos, tal vez haciendo un .ToList ()

IEnumerable:

lista de artículos solo hacia adelante. No puede llegar al "elemento 4" sin pasar los elementos 0-3. lista de solo lectura, no puede agregarla ni eliminarla. Todavía podría usar la ejecución diferida.

IList:

el acceso aleatorio a la lista completa en su totalidad en la memoria admite agregar y quitar

ICollection:

Está entre IEnumerable e IList. Lo que es "mejor" depende de sus requisitos. Por lo general, aunque un IEnumerable es "suficientemente bueno" si solo desea mostrar elementos. Al menos siempre use la variante genérica.

Zia Qammar
fuente
esta respuesta no parece añadir nada de valor sobre lo que ya ha sido publicado en las respuestas anteriores
mosquito
es solo un concepto simple sobre todo
Zia Qammar