Qual è la differenza tra List (of T) e Collection (of T)?


92

Li ho visti usati nello stesso modo e sono preoccupato di intraprendere un percorso nel design che è irreversibile se non lo capisco meglio. Inoltre, sto usando .NET.

Risposte:


50

Collection<T>è un wrapper personalizzabile IList<T>. Sebbene IList<T>non sia sigillato, non fornisce alcun punto di personalizzazione. Collection<T>I metodi di sono delegati per impostazione predefinita ai IList<T>metodi standard , ma possono essere facilmente sovrascritti per fare ciò che si desidera. È anche possibile collegare eventi all'interno di un programma Collection<T>che non credo si possano fare con un IList.

In breve, è molto più facile estenderlo dopo il fatto, il che potrebbe potenzialmente significare molto meno refactoring.


@ Marc Gravell, @Adam Lassek: Non possiamo fare la stessa cosa con un List nascondendo il metodo InsertItem (...) con un public void new InsertItem (...) e quindi chiamando base.InsertItem (.. .) dall'interno ? Non avrebbe comunque rotto il contratto. (il nome è "Inserisci" nell'elenco, ma comunque). Allora qual è il grosso problema nell'attenersi alle collezioni <T>?
DeeStackOverflow

4
@DeeStackOverflow - perché il metodo nascondiglio non verrà utilizzato da qualsiasi codice che utilizza un API diverso - vale a dire tutto ciò che sembra per IList, IList<T>, List<T>ecc In breve, non si ha idea se si chiamerà. Il polimorfismo risolve questo problema.
Marc Gravell

@AdamLassek: potresti voler aggiungere nella tua risposta ObservableCollection<T>come esempio in cui i metodi vengono ignorati per notificare le modifiche.
Kiran Challa

84

In C # ci sono tre concetti per rappresentare una borsa di oggetti. In ordine crescente di funzionalità, sono:

  • Enumerabile : non ordinato, non modificabile
  • Raccolta : può aggiungere / rimuovere elementi
  • Elenco : consente agli elementi di avere un ordine (accesso e rimozione per indice)

Enumerable non ha ordine. Non è possibile aggiungere o rimuovere elementi dal set. Non puoi nemmeno ottenere un conteggio degli elementi nel set. Ti consente rigorosamente di accedere a ogni elemento del set, uno dopo l'altro.

La raccolta è un insieme modificabile. Puoi aggiungere e rimuovere oggetti dal set, puoi anche ottenere il conteggio degli elementi nel set. Ma non c'è ancora ordine, e poiché non c'è ordine: non c'è modo di accedere a un elemento in base all'indice, né c'è alcun modo per ordinare.

La lista è un insieme ordinato di oggetti. È possibile ordinare l'elenco, accedere agli elementi per indice, rimuovere elementi per indice.

Infatti, quando si esaminano le interfacce per questi, si basano l'una sull'altra:

  • interface IEnumerable<T>

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

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

    • Insert
    • IndexOf
    • RemoveAt

Quando si dichiarano variabili o parametri di metodo, è necessario scegliere di utilizzare

  • IEnumerable
  • ICollection
  • IList

basato su concettualmente devi fare con l'insieme di oggetti.

Se hai solo bisogno di essere in grado di fare qualcosa su ogni oggetto in un elenco, allora hai solo bisogno di IEnumerable:

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

Non ti importa se gli utenti sono tenuti in un List<T>, Collection<T>, Array<T>o qualsiasi altra cosa. Hai solo bisogno IEnumerable<T>dell'interfaccia.

Se devi essere in grado di aggiungere, rimuovere o contare gli elementi in un set, utilizza una raccolta :

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

Se ti interessa un ordinamento e desideri che l'ordine sia corretto, utilizza un elenco :

IList<User> users = FetchUsers(db);

In forma di grafico:

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

La List<T>e Collection<T>in System.Collections.Genericdue classi che implementano queste interfacce; ma non sono le uniche classi:

  • ConcurrentBag<T>è un sacchetto di oggetti ordinato ( IEnumerable<T>)
  • LinkedList<T>è una borsa in cui non sei autorizzato ad accedere agli elementi tramite index ( ICollection); ma puoi aggiungere e rimuovere arbitrariamente elementi dalla raccolta
  • SynchronizedCollection<T> in una raccolta ordinata, dove è possibile aggiungere / rimuovere elementi per indice

Quindi puoi facilmente cambiare:

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

SaveEveryUser(users);

tl; dr

  • Enumerabile : accesso agli elementi, non ordinato, non modificabile
  • Raccolta - può essere modificata (aggiungi, elimina, conta)
  • Elenco : può accedere in base all'indice

Scegli il concetto di cui hai bisogno, quindi utilizza la classe corrispondente.


11
L'OP ha chiesto informazioni sui tipi concreti e hai confrontato le interfacce. Il tipo concreto Collection <T> implementa IList <T> e dispone di funzionalità di accesso tramite indice.
JJS

2
La risposta è buona ma deviata dalla domanda.Non può adattarsi alla tua risposta per le classi Collection <T> e List <T>, voglio dire dalla domanda potenziale se provo a convalidare il tuo punto semplicemente non giustificano. Per una risposta generica potresti avere ragione sul fatto che la raccolta non è ordinata quindi nessuna indicizzazione, ma l'elenco è ordinato in modo che sia possibile l'inserimento in un determinato indice.
Kylo Ren

e se dovessi avere funzionalità da ICollection <T> e anche solrting e trovare possibilità?

2
Se l'elenco è ordinato e la raccolta è priva di ordini, sarebbe un'enorme differenza funzionale per guidare facilmente un nuovo studente (come me) a scegliere. Ma aspetta, perché dici che una collezione non ha ordine? Fornisce il metodo IndexOf () e RemoveAt () , quindi È ordinato, non è vero? Mi sono perso qualcosa qui?
RayLuo

1
@RayLuo mi riferisco specificamente a ICollection<T>e IList<T>. Diverse implementazioni concrete possono comportarsi in modo diverso. Ad esempio, se accedi a a List<T>tramite la sua IEnumerable<T>interfaccia, non hai modo di aggiungere, rimuovere, ordinare o contare gli elementi nell'elenco.
Ian Boyd

43

List<T>è inteso per uso interno all'interno del codice dell'applicazione. Dovresti evitare di scrivere API pubbliche che accettano o restituiscono List<T>(considera invece l'utilizzo di una superclasse o di un'interfaccia di raccolta).

Collection<T> serve una classe base per le raccolte personalizzate (sebbene possa essere utilizzata direttamente).

Considera l'idea di utilizzarlo Collection<T>nel tuo codice a meno che non ci siano caratteristiche specifiche di List<T>cui hai bisogno.

Quanto sopra sono solo consigli.

[Adattato da: Framework Design Guidelines, Second Edition]


Vale la pena notare che i tipi che utilizzano qualsiasi tipo di oggetto mutabile per incapsulare il proprio stato dovrebbero evitare di restituire oggetti di tale tipo a meno che gli oggetti in questione non abbiano un mezzo per notificare al loro proprietario quando sono mutati, o il nome del metodo che restituisce il object implica chiaramente che sta restituendo una nuova istanza. Si noti che, ad esempio, la Dictionary<string, List<string>>restituzione di a List<string>va bene, poiché lo stato del dizionario incapsula solo le identità delle liste in esso, piuttosto che il loro contenuto.
supercat

37

List<T>è un contenitore molto comunemente visto, perché è così molto versatile (con un sacco di metodi utili come Sort, Find, ecc) - ma non ha punti di estensione, se si desidera sovrascrivere uno qualsiasi dei comportamenti (elementi di controllo su inserto, per esempio).

Collection<T>è un wrapper attorno a qualsiasi IList<T>(predefinito a List<T>) - ha i punti di estensione ( virtualmetodi), ma non tanti metodi di supporto come Find. A causa dell'indirizzamento, è leggermente più lento di List<T>, ma non di molto.

Con LINQ, i metodi supplementari List<T>diventano meno importanti, dal momento che LINQ to Objects tende a fornire loro comunque ... per esempio First(pred), OrderBy(...)e così via


6
Collection <T> manca del metodo foreach, anche in Linq-to-Objects.
tuinstoel

7
@tuinstoel - ma è banale aggiungere.
Marc Gravell

12

L'elenco è più veloce.

Fallo per esempio

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());


}

sulla mia macchina List<>è quasi il doppio più veloce.

modificare

Non riesco a capire perché la gente stia votando negativamente. Sia sulla mia macchina da lavoro che su quella di casa il codice List <> è più veloce dell'80%.


1
Com'è più veloce? Consultare? Inserimento? Rimozione? Ricerca? Perché è più veloce?
Doug T.

17
L'elenco contiene meno lettere da digitare rispetto a Collection :)
RedFilter

1
La raccolta ha meno metodi. Quindi è più veloce. QED. (scherzando, non sto trollando)
Ray

2
L'ho provato sulla mia macchina e l'elenco è circa il 20% più veloce. Sarei interessato a qualche discussione sul perché questo potrebbe essere. Forse l'elenco è migliore con l'allocazione della memoria.
Ray

10
I metodi di List non sono ereditabili quindi non ci sono controlli per vedere se sono stati ereditati; I metodi di raccolta sono ereditabili. Il vantaggio è che puoi usare Collection come classe base da cui ereditare e creare una Collection personalizzata.
Richard Gadsden

11

List rappresenta una raccolta in cui l'ordine degli elementi è importante. Supporta anche metodi come Ordina e cerca. La raccolta è una struttura dati più generale che fa meno supposizioni sui dati e supporta anche meno metodi per manipolarli. Se vuoi esporre una struttura dati personalizzata, dovresti probabilmente estendere la raccolta. Se hai bisogno di manipolare i dati senza esporre la struttura dei dati, un elenco è probabilmente il modo più conveniente per procedere.


4

Questa è una di quelle domande della scuola di specializzazione. A Collection of T è una specie di astratto; potrebbe esserci un'implementazione predefinita (non sono un tipo .net / c #) ma una raccolta avrà operazioni di base come aggiungere, rimuovere, iterare e così via.

L'elenco di T implica alcune specifiche su queste operazioni: add dovrebbe richiedere tempo costante, remove dovrebbe richiedere tempo proporzionale al numero di elementi, getfirst dovrebbe essere tempo consant. In generale, un elenco è un tipo di raccolta, ma una raccolta non è necessariamente un tipo di elenco.


4

Hanselman Speaks : " Collection<T>sembra un elenco, e ha anche List<T>internamente. OGNI singolo metodo delega a quello interno List<T>. Include una proprietà protetta che espone il List<T>."

EDIT: Collection<T>non esiste in System.Generic.Collections .NET 3.5. Se esegui la migrazione da .NET 2.0 a 3.5, dovrai modificare del codice se ne utilizzi moltiCollection<T> oggetti, a meno che non mi manchi qualcosa di ovvio ...

EDIT 2: Collection<T>è ora nello spazio dei nomi System.Collections.ObjectModel in .NET 3.5. Il file della guida dice questo:

"Lo spazio dei nomi System.Collections.ObjectModel contiene classi che possono essere utilizzate come raccolte nel modello a oggetti di una libreria riutilizzabile. Utilizzare queste classi quando proprietà o metodi restituiscono raccolte."


4

Tutte queste interfacce ereditano da IEnumerable, che dovresti assicurarti di capire. Quell'interfaccia fondamentalmente ti consente di usare la classe in un'istruzione foreach (in C #).

  • ICollectionè la più semplice delle interfacce che hai elencato. È un'interfaccia enumerabile che supporta a Counte questo è tutto.
  • IListè tutto ciò che ICollectionè, ma supporta anche l'aggiunta e la rimozione di elementi, il recupero di elementi per indice, ecc. È l'interfaccia più comunemente usata per "elenchi di oggetti", il che è vago lo so.
  • IQueryableè un'interfaccia enumerabile che supporta LINQ. Puoi sempre creare un IQueryableda un IList e usare LINQ to Objects, ma puoi anche trovare IQueryableusato per l'esecuzione differita di istruzioni SQL in LINQ to SQL e LINQ to Entities.
  • IDictionaryè un animale diverso nel senso che è una mappatura di chiavi uniche di valori. È anche enumerabile in quanto puoi enumerare le coppie chiave / valore, ma per il resto ha uno scopo diverso rispetto agli altri che hai elencato

ICollection supporta l'aggiunta / rimozione / cancellazione: msdn.microsoft.com/en-us/library/…
amnesia

4

Secondo MSDN, List (Of T) .Add è "un'operazione O (n)" (quando la "Capacità" viene superata) mentre Collection (Of T) .Add è sempre "un'operazione O (1)". Ciò sarebbe comprensibile se List fosse implementato utilizzando un array e Collection un elenco collegato. Tuttavia, se così fosse, ci si aspetterebbe che Collection (Of T) .Item sia "un'operazione O (n)". Ma - non è - non !?! Collection (Of T) .Item è "un'operazione O (1)" proprio come List (Of T) .Item.

Inoltre, il post di "tuinstoel" "Dec 29 '08 at 22:31" sopra i test di velocità delle affermazioni mostra List (Of T) .Aggiungi per essere più veloce della Collection (Of T) .Aggiungi che ho riprodotto con Di Long e di String. Anche se sono diventato più veloce di circa il 33% rispetto al suo 80% dichiarato, secondo MSDN, avrebbe dovuto essere il contrario e di "n" volte!?!


3

Entrambi implementano le stesse interfacce, quindi si comporteranno allo stesso modo. Forse sono implementati internamente in modo diverso, ma questo dovrebbe essere testato.

Le uniche differenze reali che vedo sono gli spazi dei nomi e il fatto che Collection<T>è contrassegnato con ComVisibleAttribute(false), quindi il codice COM non può usarlo.


Implementano interfacce diverse: List <T> implementa IList <T>, mentre Collection <T> non lo fa.
Bevan

@Bevan provalo in c #, entrambi implementano lo stesso set di interfacce
Kylo Ren

1
Questo è un interessante @KyloRen cambiamento - che fanno ora implementano sia lo stesso insieme di interfacce; questo non era il caso nel '08.
Bevan

1
@Bevan interessante. Non sono sicuro di quale fosse la ragione di due classi diverse, una con solo alcuni metodi extra.
Kylo Ren

3

Oltre ad altri asnwers, ho compilato una rapida panoramica delle funzionalità di raccolta e elenco generico. La raccolta è un sottoinsieme limitato dell'elenco:

* = presente 
o = parzialmente presente

Raccolta proprietà / metodi < T > Elenco < 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()                        *
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.