Differenza tra varie interfacce generiche di raccolta in C #


11

Da tempo gioco con C # per Windows e ASP.net per lo sviluppo MVC. Ma non sono ancora chiaro in alcune aree. Sto cercando di comprendere la differenza di base tra e problemi di prestazioni con l'utilizzo e lo scambio di tipi simili di interfacce di raccolta generiche .

Qual è la differenza fondamentale tra IEnumerable<T>, ICollection<T>, List<T>(Class)?

Mi sembra di usarli e scambiarli senza vedere alcun problema nelle mie applicazioni. Inoltre, ci sono altre raccolte generiche simili come queste che possono essere scambiate con quelle tre?


2
c'è anche IList <T>
jk.

Risposte:


19

Elenco <T> è una classe e implementa entrambe le interfacce ICollection <T> e IEnumerable <T> . Inoltre, ICollection <T> estende l'interfaccia IEnumerable <T>. Non sono intercambiabili, almeno non da tutti i punti di vista.

Se si dispone di un Elenco <T>, si garantisce che questo oggetto implementa i metodi e le proprietà richiesti per essere implementati dall'interfaccia ICollection <T> e IEnumerable <T>. Il compilatore lo sa e ti è permesso di lanciarli "verso il basso" in una ICollection <T> o in un IEnumerable <T> implicitamente. Tuttavia, se hai un ICollection <T> devi prima controllare esplicitamente nel tuo codice se è un Elenco <T> o qualcos'altro, forse un Dizionario <T> (dove T è un KeyValuePair ) prima di lanciarlo in quello che desiderio.

Sai che ICollection estende IEnumerable, quindi puoi eseguirne il cast in un IEnumerable. Ma se hai solo un IEnumerable, di nuovo non hai la garanzia che sia un Elenco. Potrebbe essere, ma potrebbe essere qualcos'altro. Dovresti aspettarti un'eccezione di cast non valida se provi ad esempio a lanciare un Elenco <T> in un dizionario <T>.

Quindi non sono "intercambiabili".

Inoltre, ci sono molte interfacce generiche, controlla cosa puoi trovare nello spazio dei nomi System.Collections.Generic .

Modifica: per quanto riguarda il tuo commento, non c'è assolutamente alcuna penalità per le prestazioni se usi List <T> o una delle interfacce che implementa. Dovrai comunque creare un nuovo oggetto, controlla il seguente codice:

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

list , myColl e myEnum puntano tutti allo stesso oggetto. Sia che tu lo dichiari come Elenco o ICollection o IEnumerable, sto ancora richiedendo al programma di creare un Elenco. Avrei potuto scrivere questo:

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

myColl , in fase di esecuzione è ancora un elenco.

Tuttavia , questo è il punto più importante ... per ridurre l'accoppiamento e aumentare la manutenibilità dovresti sempre dichiarare le tue variabili e i parametri del metodo usando il minimo denominatore possibile per te, che si tratti di un'interfaccia o di una classe astratta o concreta.

Immagina che l'unica cosa di cui il metodo "PerformOperation" ha bisogno è enumerare gli elementi, fare un po 'di lavoro ed uscire, in tal caso non hai bisogno dei cento metodi disponibili in Elenco <T>, hai solo bisogno di ciò che è disponibile in IEnumerable <T >, quindi è necessario applicare quanto segue:

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

In questo modo, tu e altri sviluppatori sapete che qualsiasi oggetto di una classe che implementa l'interfaccia IEnumerable <T> può essere assegnato a questo metodo. Può essere un elenco, un dizionario o una classe di raccolta personalizzata scritta da un altro sviluppatore.

Se al contrario specifichi che hai esplicitamente bisogno di un Elenco concreto <T> (e sebbene raramente sia il caso nella vita reale, può ancora succedere), tu e altri sviluppatori sapete che deve essere un Elenco o un'altra eredità di una classe concreta dalla lista.


Innanzitutto grazie. Ora, il punto di preoccupazione è come decidere quale usare ??. Poiché List <T> implementa entrambe le interfacce, perché non utilizzarlo sempre in ogni luogo in cui è richiesto IEnumerable o ICollection. L'utilizzo dell'elenco avrà sempre un impatto sulle prestazioni? Modifica la tua risposta per rispondere a queste preoccupazioni
Pankaj Upadhyay,

Ho modificato per rispondere alle tue domande sulla performance
Jalayn

+1, ma aggiungerei che nei rari casi in cui è effettivamente necessario il passaggio di un elenco a un metodo, è necessario utilizzare IListanziché Listnella dichiarazione del metodo.
Konamiman,

@Konamiman - Dipende se hai bisogno di List<>funzionalità specifiche, come .AddRange(). Questo IList<>non lo svela.
Bobson,

6

Dai un'occhiata alle pagine MSDN per ICollection e IEnumerable .

In termini molto astratti, è così che concepisco questi tipi.

Un IEnumerable è tutto ciò che può essere enumerato, ovvero ripetuto. Non significa necessariamente una "collezione"; ad esempio, IQueryable implementa IEnumerable e non è una raccolta, ma è qualcosa su cui è possibile eseguire query per restituire oggetti. Per implementare IEnumerable un oggetto deve solo essere in grado di restituire un oggetto quando viene interrogato. Potrei dire che ho un gran numero di compiti che farò oggi (non è un elenco perché non l'ho scritto o formulato, ma potrei dirti cosa farò ora, e se hai chiesto "e poi?" sarei in grado di dirti il ​​seguente compito).

Un ICollection è più concreto di un IEnumerable. Una differenza fondamentale è che una collezione sa quanti elementi contiene; per capire quanti elementi ci sono in un Enumerable, esegui il ciclo e contali efficacemente:

Io: Ragazzi, quanti oggetti avete ciascuno in voi?

Enumerabile: non lo so davvero. Bene, ecco un oggetto. Ne ho un altro, quindi sono due. E un altro, quindi sono tre ... e un altro ... ok, quindi è 2382. Niente più oggetti, quindi ho 2382. Non chiedermelo più perché dovrò esaminarli di nuovo tutti.

Collezione: ho 2382 articoli. Lo so già.

Una raccolta è in genere qualcosa che sa già dove sono tutti i suoi elementi e non dovrà andare a trovarli o generarli quando li chiedi. È più ... concreto di un enumerabile.

A mio avviso, la differenza tra un Enumerable e una Collection è molto più grande della differenza tra una Collection e una Lista. In effetti, faccio fatica a pensare a una differenza pratica tra una collezione e una lista, ma credo che la lista offra metodi migliori per la ricerca e l'ordinamento.

Altri tipi di raccolta includono Queuee Stack, oltre a Dictionary.

I nomi di questi tipi sono abbastanza utili: puoi concepire una coda e uno stack come le loro controparti del mondo reale e considerare le differenze che potresti avere con un Elenco.


"Sto lottando per pensare a una differenza pratica tra una collezione e una lista" ... Più avanti nella tua risposta rispondi tu stesso. Una Listè una ICollection, ma una ICollectionnon è sempre un List( Queue, Stack, Dictionary, ...)
Steven Jeuris

@Steven È una risposta molto sconclusionata. Sono d'accordo che questa è una differenza importante, ma non la definirei una differenza pratica. Cosa significa per l'utente?
Kirk Broadhurst,

Questo è facile! :) Queue<int> queue = (Queue<int>)list;genererà un InvalidCastExceptionquando listnon è un Queue<int>. La differenza tra la coda e l'elenco non rientra nell'ambito di questa domanda.
Steven Jeuris,

Non è l'aspetto critico di IEnumerable il fatto che possa restituire gli elementi attuali e successivi - in qualche modo alludi a quello, ma non lo dici esplicitamente. Essenzialmente qualcosa che implementa IEnumerable da solo non può restituire un elemento arbitrario dei suoi membri quando viene interrogato - solo quello corrente e quello successivo.
cori,

@cori Questo è un modo molto conciso di dirlo, molto più chiaro della mia risposta.
Kirk Broadhurst,

-1

IQueryable:

la query non viene eseguita fino a quando non si esegue realmente l'iterazione degli elementi, magari eseguendo un .ToList ()

IEnumerable:

elenco di elementi forward only. Non puoi arrivare all '"oggetto 4" senza passare gli oggetti 0-3. elenco di sola lettura, non è possibile aggiungerlo o rimuoverlo. Potrebbe ancora utilizzare l'esecuzione differita.

IList:

l'accesso casuale all'elenco completo interamente in memoria supporta l'aggiunta e la rimozione

ICollection:

È tra IEnumerable e IList. Ciò che è "migliore" dipende dalle tue esigenze. Di solito però un IEnumerable è "abbastanza buono" se si desidera solo visualizzare elementi. Almeno usa sempre la variante generica.


questa risposta non sembra aggiungere nulla di prezioso rispetto a ciò che è già stato pubblicato in risposte precedenti
moscerino

è solo un semplice concetto di tutto
Zia Qammar,
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.