¿Cuál es la diferencia entre Lista (de T) y Colección (de T)?

93

Los he visto usados ​​de muchas maneras similares, y me preocupa estar a punto de tomar un camino en el diseño que es irreversible si no entiendo esto mejor. Además, estoy usando .NET.

Anthony Potts
fuente

Respuestas:

50

Collection<T>es un envoltorio personalizable IList<T>. Si bien IList<T>no está sellado, no proporciona ningún punto de personalización. Collection<T>Los métodos de 'se delegan de forma predeterminada a los IList<T>métodos estándar , pero se pueden anular fácilmente para hacer lo que desee. También es posible conectar eventos dentro de un Collection<T>que no creo que se pueda hacer con un IList.

En resumen, es mucho más fácil extenderlo después del hecho, lo que potencialmente podría significar una refactorización mucho menor.

Adam Lassek
fuente
@Marc Gravell, @Adam Lassek: ¿No podemos hacer lo mismo con una Lista ocultando el método InsertItem (...) con un nuevo InsertItem (...) vacío público y luego llamando a la base.InsertItem (.. .) desde dentro? Todavía no rompería el contrato. (el nombre es 'Insertar' en la Lista, pero no obstante). Entonces, ¿cuál es el problema de ceñirse a las Colecciones <T>?
DeeStackOverflow
4
@DeeStackOverflow - porque escondite método no será utilizada por cualquier código que utiliza una API diferente - es decir, cualquier cosa que parezca para IList, IList<T>, List<T>etc. En definitiva, que no tienen ni idea de si se va a llamar. El polimorfismo soluciona esto.
Marc Gravell
@AdamLassek: es posible que desee agregar en su respuesta acerca de ObservableCollection<T>como un ejemplo donde los métodos se anulan para notificar sobre cambios.
Kiran Challa
84

En C #, hay tres conceptos para representar una bolsa de objetos. En orden de características crecientes, son:

  • Enumerable : no ordenado, no modificable
  • Colección : puede agregar / eliminar elementos
  • Lista : permite que los elementos tengan un orden (acceder y eliminar por índice)

Enumerable no tiene orden. No puede agregar o eliminar elementos del conjunto. Ni siquiera puede obtener un recuento de elementos en el conjunto. Te permite acceder estrictamente a cada elemento del conjunto, uno tras otro.

La colección es un conjunto modificable. Puede agregar y eliminar objetos del conjunto, también puede obtener el recuento de elementos en el conjunto. Pero todavía no hay orden, y como no hay orden: no hay forma de acceder a un elemento por índice, ni hay forma de ordenar.

La lista es un conjunto ordenado de objetos. Puede ordenar la lista, acceder a elementos por índice, eliminar elementos por índice.

De hecho, al mirar las interfaces de estos, se basan entre sí:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

Al declarar variables o parámetros de método, debe optar por utilizar

  • IEnumerable
  • ICollection
  • IList

basado en conceptualmente lo que necesita hacer con el conjunto de objetos.

Si solo necesita poder hacer algo con cada objeto en una lista, entonces solo necesita IEnumerable:

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

No te importa si los usuarios se mantienen en una List<T>, Collection<T>, Array<T>o cualquier otra cosa. Solo necesitas la IEnumerable<T>interfaz.

Si necesita poder agregar, eliminar o contar los elementos de un conjunto, utilice una colección :

ICollection<User> users = new Collection<User>();
users.Add(new User());

Si le interesa un orden de clasificación y necesita que el orden sea correcto, utilice una Lista :

IList<User> users = FetchUsers(db);

En forma de gráfico:

| Feature                | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items      | X              | X              | X        |
|                        |                |                |          |
| Adding items           |                | X              | X        |
| Removing items         |                | X              | X        |
| Count of items         |                | X              | X        |
|                        |                |                |          |
| Accessing by index     |                |                | X        |
| Removing by indexx     |                |                | X        |
| Getting index of item  |                |                | X        |

El List<T>y Collection<T>en System.Collections.Genericdos clases que implementan estas interfaces; pero no son las únicas clases:

  • ConcurrentBag<T>es una bolsa ordenada de objetos ( IEnumerable<T>)
  • LinkedList<T>es una bolsa en la que no se le permite acceder a elementos por index ( ICollection); pero puede agregar y eliminar elementos de la colección de forma arbitraria
  • SynchronizedCollection<T> en una colección ordenada, donde puede agregar / eliminar elementos por índice

Para que pueda cambiar fácilmente:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

tl; dr

  • Enumerable : elementos de acceso, no ordenados, no modificables
  • Colección : se puede modificar (agregar, eliminar, contar)
  • Lista : se puede acceder por índice

Elija el concepto que necesita, luego use la clase correspondiente.

Ian Boyd
fuente
11
El OP preguntó sobre los tipos concretos y ha comparado las interfaces. El tipo concreto Collection <T> implementa IList <T> y tiene capacidades de acceso por índice.
JJS
2
La respuesta es buena pero se desvió de la pregunta. No se ajusta a su respuesta para las clases Collection <T> y List <T>, me refiero a la pregunta prospectiva si trato de validar su punto, simplemente no se justifican. Para una respuesta de propósito general, puede tener razón en que la colección no está ordenada, por lo que no hay indexación, pero la lista está ordenada para que la inserción sea posible en un índice determinado.
Kylo Ren
¿Y si tuviera características de ICollection <T> y también resolviera y encontrara la posibilidad?
2
Si la lista está ordenada y la colección no lo está, sería una gran diferencia funcional para guiar fácilmente a un nuevo alumno (como yo) a elegir. Pero espera, ¿por qué dices que una colección no tiene orden? Proporciona el método IndexOf () y RemoveAt () , por lo que está ordenado, ¿no? ¿Me perdí algo aquí?
RayLuo
1
@RayLuo me refiero específicamente a ICollection<T>y IList<T>. Diferentes implementaciones concretas pueden comportarse de manera diferente. Por ejemplo, si accede a a List<T>través de su IEnumerable<T>interfaz, entonces no tiene forma de agregar, eliminar, ordenar o contar elementos en la lista.
Ian Boyd
43

List<T>está diseñado para uso interno dentro del código de la aplicación. Debe evitar escribir API públicas que acepten o devuelvan List<T>(considere usar una superclase o una interfaz de colección en su lugar).

Collection<T> sirve como clase base para colecciones personalizadas (aunque se puede usar directamente).

Considere usar Collection<T>en su código a menos que haya características específicas List<T>que necesite.

Lo anterior son solo recomendaciones.

[Adaptado de: Framework Design Guidelines, segunda edición]

Arnold Zokas
fuente
Vale la pena señalar que los tipos que usan cualquier tipo de objetos mutables para encapsular su propio estado deben evitar devolver objetos de ese tipo a menos que los objetos en cuestión tengan un medio para notificar a su propietario cuando están mutados, o el nombre del método que devuelve el El objeto claramente implica que está devolviendo una nueva instancia. Tenga en cuenta que, por ejemplo, a Dictionary<string, List<string>>to return List<string>está bien, ya que el estado del diccionario solo encapsula las identidades de las listas en él, en lugar de su contenido.
supercat
37

List<T>es un recipiente muy comúnmente visto, porque es muy muy versátil (con un montón de métodos útiles como Sort, Find, etc.) - pero no tiene puntos de extensión si desea anular alguna de las conductas (elementos de comprobación en el inserto, por ejemplo).

Collection<T>es un contenedor alrededor de cualquiera IList<T>(por defecto List<T>): tiene los puntos de extensión ( virtualmétodos), pero no tantos métodos de soporte como Find. Debido a la indirección, es un poco más lento que List<T>, pero no mucho.

Con LINQ, los métodos adicionales en List<T>llegar a ser menos importante, ya que LINQ a objetos tiende a proporcionar todos modos ... por ejemplo First(pred), OrderBy(...), etc.

Marc Gravell
fuente
6
Collection <T> carece de método foreach, incluso en Linq-to-Objects.
Tuinstoel
7
@tuinstoel, pero es trivial de agregar.
Marc Gravell
12

La lista es más rápida.

Hacer por ejemplo

private void button1_Click(object sender, EventArgs e)
{
  Collection<long> c = new Collection<long>();
  Stopwatch s = new Stopwatch();
  s.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    c.Add(i);
  }
  s.Stop();
  MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());

  List<long> l = new List<long>();
  Stopwatch s2 = new Stopwatch();
  s2.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    l.Add(i);
  }
  s2.Stop();
  MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());


}

en mi máquina List<>es casi el doble de rápido.

Editar

No puedo entender por qué la gente está rechazando esto. Tanto en mi máquina de trabajo como en mi máquina doméstica, el código List <> es un 80% más rápido.

tuinstoel
fuente
1
¿Cómo es más rápido? ¿Buscar? ¿Inserción? ¿Eliminación? ¿Buscar? ¿Por qué es más rápido?
Doug T.
17
La lista tiene menos letras para escribir que la colección :)
RedFilter
1
La colección tiene menos métodos. Por tanto, es más rápido. QED. (bromeando, no estoy trolling)
Ray
2
Lo probé en mi máquina y la lista es aproximadamente un 20% más rápida. Estaría interesado en alguna discusión sobre por qué podría ser esto. Quizás la lista sea mejor con la asignación de memoria.
Ray
10
Los métodos de la lista no son heredables, por lo que no hay comprobaciones para ver si se han heredado; Los métodos de la colección son heredables. La ventaja es que puede usar Colección como una clase base para heredar y crear una Colección personalizada.
Richard Gadsden
11

La lista representa una colección donde el orden de los elementos es importante. También es compatible con los métodos de clasificación y búsqueda. La recopilación es una estructura de datos más general que hace menos suposiciones sobre los datos y también admite menos métodos para manipularlos. Si desea exponer una estructura de datos personalizada, probablemente debería extender la colección. Si necesita manipular datos sin exponer la estructura de datos, una lista es probablemente la forma más conveniente de hacerlo.

Manu
fuente
4

Esta es una de esas preguntas de la escuela de posgrado. Una colección de T es una especie de abstracto; puede haber una implementación predeterminada (no soy un tipo .net / c #) pero una colección tendrá operaciones básicas como agregar, eliminar, iterar, etc.

La lista de T implica algunos detalles sobre estas operaciones: agregar debe tomar un tiempo constante, eliminar debe tomar un tiempo proporcional al número de elementos, getfirst debe ser un tiempo constante. En general, una lista es una especie de colección, pero una colección no es necesariamente una especie de lista.

Charlie martin
fuente
4

Hanselman Speaks : " Collection<T>parece una lista, e incluso tiene List<T>internamente. CADA método delega al interno List<T>. Incluye una propiedad protegida que expone el List<T>."

EDITAR: Collection<T>no existe en System.Generic.Collections .NET 3.5. Si migra de .NET 2.0 a 3.5, deberá cambiar algo de código si está usando muchos Collection<T>objetos, a menos que me esté perdiendo algo obvio ...

EDIT 2: Collection<T>ahora está en el espacio de nombres System.Collections.ObjectModel en .NET 3.5. El archivo de ayuda dice esto:

"El espacio de nombres System.Collections.ObjectModel contiene clases que se pueden usar como colecciones en el modelo de objetos de una biblioteca reutilizable. Use estas clases cuando las propiedades o los métodos devuelvan colecciones".

Tad Donaghe
fuente
4

Todas estas interfaces heredan IEnumerable, de las que debe asegurarse de comprender. Esa interfaz básicamente le permite usar la clase en una declaración foreach (en C #).

  • ICollectiones la más básica de las interfaces que enumeró. Es una interfaz enumerable que admite a County eso es todo.
  • IListes todo lo que ICollectiones, pero también admite agregar y eliminar elementos, recuperar elementos por índice, etc. Es la interfaz más utilizada para "listas de objetos", que es vaga, lo sé.
  • IQueryablees una interfaz enumerable que admite LINQ. Siempre puede crear una IQueryabledesde una IList y usar LINQ to Objects, pero también se IQueryableusa para la ejecución diferida de declaraciones SQL en LINQ to SQL y LINQ to Entities.
  • IDictionaryes un animal diferente en el sentido de que es un mapeo de claves únicas para valores. También es enumerable porque puede enumerar los pares clave / valor, pero por lo demás tiene un propósito diferente al de los demás que enumeró.
Raj Gupta
fuente
ICollection admite agregar / eliminar / borrar: msdn.microsoft.com/en-us/library/…
amnesia
4

Según MSDN, List (Of T) .Add es "una operación O (n)" (cuando se excede la "Capacidad") mientras que Collection (Of T) .Add es siempre "una operación O (1)". Eso sería comprensible si la lista se implementa utilizando una matriz y una colección una lista vinculada. Sin embargo, si ese fuera el caso, se esperaría que Collection (Of T) .Item sea "una operación O (n)". Pero - es - no !?! Collection (Of T) .Item es "una operación O (1)" al igual que List (Of T) .Item.

Además de eso, la publicación de "29 de diciembre de 2008 a las 22:31" de "tuinstoel" sobre las afirmaciones de las pruebas de velocidad muestran List (Of T) .Add para ser más rápido que Collection (Of T) .Add que he reproducido con Long y String. Aunque solo obtuve ~ 33% más rápido en comparación con el 80% que afirmaba, según MSDN, ¡debería haber sido lo contrario y por "n" veces!?!

Tom
fuente
3

Ambos implementan las mismas interfaces, por lo que se comportarán de la misma manera. Quizás se implementen de manera diferente internamente, pero esto tendría que ser probado.

Las únicas diferencias reales que veo son los espacios de nombres y el hecho de que Collection<T>está marcado con ComVisibleAttribute(false), por lo que el código COM no puede usarlo.

OwenP
fuente
Implementan diferentes interfaces: List <T> implementa IList <T>, mientras que Collection <T> no.
Bevan
@Bevan pruébalo en c #, ambos implementan el mismo conjunto de interfaces
Kylo Ren
1
Esa es una interesante @KyloRen cambio - que no aplican hoy día tanto en el mismo conjunto de interfaces; este no era el caso en el 2008.
Bevan
1
@Bevan interesante. No estoy seguro de cuál fue la razón de dos clases diferentes, una con solo algunos métodos adicionales.
Kylo Ren
3

Además de otras respuestas, he compilado una descripción general rápida de las capacidades de recopilación y lista genérica. La colección es un subconjunto limitado de la Lista:

* = presente 
o = parcialmente presente

Propiedad / Método Colección < T > Lista < T > --------------------------------------- -------      

Add()                *              *
AddRange()                          *
AsReadOnly()                        *
BinarySearch()                      *
Capacity                            *
Clear()              *              *
Contains()           *              *
ConvertAll()                        *
CopyTo()             o              *
Count                *              *
Equals()             *              *
Exists()                            *
Find()                              *
FindAll()                           *
FindIndex()                         *
FindLast()                          *
FindLastIndex()                     *
ForEach()                           *
GetEnumerator()      *              *
GetHashCode()        *              *
GetRange()                          *
GetType()            *              *
IndexOf()            o              *
Insert()             *              *
InsertRange()                       *
Item()               *              *
LastIndexOf()                       *
New()                o              *
ReferenceEquals()    *              *
Remove()             *              *
RemoveAll()                         *
RemoveAt()           *              *
RemoveRange()                       *
Reverse()                           *
Sort()                              *
ToArray()                           *
ToString()           *              *
TrimExcess()                        *
TrueForAll()                        *
miroxlav
fuente