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.