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.
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:
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.
IList
, IList<T>
, List<T>
ecc In breve, non si ha idea se si chiamerà. Il polimorfismo risolve questo problema.
ObservableCollection<T>
come esempio in cui i metodi vengono ignorati per notificare le modifiche.
In C # ci sono tre concetti per rappresentare una borsa di oggetti. In ordine crescente di funzionalità, sono:
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
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.Generic
due 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 raccoltaSynchronizedCollection<T>
in una raccolta ordinata, dove è possibile aggiungere / rimuovere elementi per indiceQuindi puoi facilmente cambiare:
IEnumerable<User> users = new SynchronizedCollection<User>();
SaveEveryUser(users);
Scegli il concetto di cui hai bisogno, quindi utilizza la classe corrispondente.
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.
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]
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.
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 ( virtual
metodi), 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
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%.
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.
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.
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."
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 Count
e 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 IQueryable
da un IList e usare LINQ to Objects, ma puoi anche trovare IQueryable
usato 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 elencatoSecondo 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!?!
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.
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() *