Perché usare ICollection e non IEnumerable o List <T> su relazioni molti-molti / uno-molti?


359

Lo vedo molto nei tutorial, con proprietà di navigazione come ICollection<T>.

È un requisito obbligatorio per Entity Framework? Posso usare IEnumerable?

Qual è lo scopo principale dell'utilizzo ICollectionanziché IEnumerableo addirittura List<T>?

Risposte:


440

Di solito ciò che scegli dipenderà da quali metodi devi accedere. In generale - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx ) per un elenco di oggetti che devono solo essere ripetuti, ICollection<>(MSDN: http: // msdn.microsoft.com/en-us/library/92t2ye13.aspx ) per un elenco di oggetti che devono essere ripetuti e modificati, List<>per un elenco di oggetti che devono essere ripetuti, modificati, ordinati, ecc. (Vedi qui per un elenco completo: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx ).

Da un punto di vista più specifico, il caricamento lento arriva a giocare con la scelta del tipo. Per impostazione predefinita, le proprietà di navigazione in Entity Framework vengono fornite con il rilevamento delle modifiche e sono proxy. Per poter creare il proxy dinamico come proprietà di navigazione, è necessario implementare il tipo virtuale ICollection.

Una proprietà di navigazione che rappresenta le "molte" estremità di una relazione deve restituire un tipo che implementa ICollection, dove T è il tipo di oggetto all'altra estremità della relazione. - Requisiti per la creazione di proxy POCO MSDN

Ulteriori informazioni sulla definizione e gestione delle relazioni MSDN


2
quindi, con quello, Listdovrebbe essere molto meglio, sì?
Jan Carlo Viray,

3
@JanCarloViray - Tendo a usare Listmolto. Sebbene abbia il maggior sovraccarico, offre la maggior funzionalità.
Travis J,

1
Gli elenchi sono definiti più dai loro indicizzatori che dalla possibilità di ordinarli (avere un indicizzatore intero rende facile ordinare qualcosa, ma non è un requisito).
phoog

2
Per quanto riguarda la modifica, limitare una proprietà a un tipo di interfaccia non riguarda la memoria ma l'incapsulamento. Considera: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };usa la stessa memoria diprivate List<int> _integers = new List<int> { 1, 2, 3 };
phoog

13
@TravisJ: List<T>ha un GetEnumerator()metodo, separato dalla sua implementazione di IEnumerable<T>, che restituisce un tipo di struttura mutabile List<T>.Enumerator. Nella maggior parte dei contesti, quel tipo produrrà prestazioni leggermente migliori rispetto a un oggetto heap autonomo. I compilatori che gli enumeratori di tipo duck (come fanno sia C # che vb.net) possono trarre vantaggio da questo durante la generazione del foreachcodice. Se List<T>viene eseguito il cast IEnumrable<T>prima di foreach, il IEnumerable<T>.GetEnumerator()metodo restituirà un oggetto allocato in heap, rendendo impossibile l'ottimizzazione.
supercat,

86

ICollection<T>viene utilizzato perché l' IEnumerable<T>interfaccia non consente di aggiungere elementi, rimuovere elementi o modificare in altro modo la raccolta.


3
che dire del confronto con List <T>?
Jan Carlo Viray,

12
List<T>implementa ICollection<T>.
spender

Il non generico ICollectionnon consente in alcun modo di aggiungere elementi, ma è comunque utile in aggiunta IEnumerable<T>perché fornisce un Countmembro che è in genere molto più veloce dell'enumerazione di tutto. Si noti che se un IList<Cat>o ICollection<Cat>viene passato al codice in attesa di un IEnumerable<Animal>, il Count()metodo di estensione sarà veloce se implementa il non generico ICollection, ma non se implementa solo le interfacce generiche poiché un tipico ICollection<Cat>non implementerà ICollection<Animal>.
Supercat,

58

Rispondere alla tua domanda su List<T>:

List<T>è una classe; la specifica di un'interfaccia consente una maggiore flessibilità di implementazione. Una domanda migliore è "perché no IList<T>?"

Per rispondere a questa domanda, considera cosa si IList<T>aggiunge a ICollection<T>: indicizzazione di numeri interi, il che significa che gli articoli hanno un ordine arbitrario e possono essere recuperati facendo riferimento a quell'ordine. Questo probabilmente non è significativo nella maggior parte dei casi, poiché gli articoli devono probabilmente essere ordinati in modo diverso in contesti diversi.


21

Esistono alcune differenze di base tra ICollection e IEnumerable

  • IEnumerable : contiene solo il metodo GetEnumerator per ottenere Enumerator e consente il looping
  • ICollection contiene metodi aggiuntivi: Aggiungi, Rimuovi, Contiene, Conta, Copia
  • ICollection è ereditato da IEnumerable
  • Con ICollection è possibile modificare la raccolta utilizzando i metodi come aggiungi / rimuovi. Non hai la libertà di fare lo stesso con IEnumerable.

Programma semplice:

using System;
using System.Collections;
using System.Collections.Generic;

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Jack", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

13

Lo ricordo così:

  1. IEnumerable ha un metodo GetEnumerator () che consente di leggere i valori in una raccolta ma non di scrivere su di essa. La maggior parte della complessità dell'uso dell'enumeratore è gestita da noi per ogni istruzione in C #. IEnumerable ha una proprietà: Current, che restituisce l'elemento corrente.

  2. ICollection implementa IEnumerable e aggiunge alcune proprietà aggiuntive la maggior parte delle quali è Count. La versione generica di ICollection implementa i metodi Add () e Remove ().

  3. IList implementa sia IEnumerable che ICollection e aggiunge l'accesso di indicizzazione di numeri interi agli articoli (cosa che di solito non è richiesta, poiché l'ordinamento viene eseguito nel database).


4
Sulla base di ciò che hai scritto ICollection e IList sono gli stessi. Aggiungi ciò che viene aggiunto a IList che non esiste in ICollection.
scommesse il

ICollection VS IList, interfaccia solo IList in System.Collection che contiene tutte le funzionalità di IEnumerable e ICollection e funzionalità aggiuntive. IList ha i metodi Inserisci e Rimuovi. Entrambi i metodi accettano l'indice nel loro parametro. Pertanto, supporta le operazioni basate sull'indice rispetto alla raccolta.
E.Meir,

7

L'idea di base dell'utilizzo ICollectionè di fornire un'interfaccia per l'accesso in sola lettura a una quantità limitata di dati. In effetti hai una proprietà ICollection.Count . IEnumerableè più adatto per alcune catene di dati in cui si legge fino a un certo punto logico, una condizione esplicitamente specificata dal consumatore o fino alla fine dell'enumerazione.


14
TIL che ICollectionè di sola lettura mentre ICollection<T>non lo è.
Carl G,

2

Le proprietà di navigazione sono in genere definite virtuali in modo da poter sfruttare alcune funzionalità di Entity Framework come il caricamento lento.

Se una proprietà di navigazione può contenere più entità (come nelle relazioni molti-a-molti o da uno a molti), il suo tipo deve essere un elenco in cui è possibile aggiungere, eliminare e aggiornare le voci, ad esempio ICollection.

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net- MVC-applicazione


2

Quello che ho fatto in passato è dichiarare le mie raccolte di classi interne usando IList<Class>, ICollection<Class>o IEnumerable<Class>(se elenco statico) a seconda che dovrò o meno fare un numero qualsiasi dei seguenti in un metodo nel mio repository: enumera, ordina / ordina o modifica . Quando ho solo bisogno di enumerare (e forse ordinare) su oggetti, allora creo un temp List<Class>per lavorare con la raccolta all'interno di un metodo IEnumerable. Penso che questa pratica sarebbe efficace solo se la raccolta fosse relativamente piccola, ma potrebbe essere una buona pratica in generale, idk. Per favore, correggimi se ci sono prove del perché questa non sarebbe una buona pratica.


0

Proviamo a pensare fuori dagli schemi con / per logica e comprendere chiaramente queste tre interfacce nella tua domanda:

Quando la classe di qualche istanza implementa l'interfaccia System.Collection.IEnumerable allora, in parole semplici, possiamo dire che questa istanza è sia enumerabile che iterabile, il che significa che questa istanza consente in qualche modo in un singolo ciclo di andare / ottenere / passare / attraversa / scorre su / attraverso tutti gli elementi e gli elementi che contiene questa istanza.

Ciò significa che è anche possibile enumerare tutti gli elementi e gli elementi contenuti in questa istanza.

Ogni classe che implementa l'interfaccia System.Collection.IEnumerable implementa anche il metodo GetEnumerator che non accetta argomenti e restituisce un'istanza System.Collections.IEnumerator.

Le istanze dell'interfaccia System.Collections.IEnumerator si comportano in modo molto simile agli iteratori C ++.

Quando la classe di qualche istanza implementa l'interfaccia System.Collection.ICollection, in parole semplici, possiamo dire che questa istanza è una raccolta di cose.

La versione generica di questa interfaccia, ovvero System.Collection.Generic.ICollection, è più informativa perché questa interfaccia generica indica esplicitamente quale sia il tipo di cose nella raccolta.

Tutto ciò è ragionevole, razionale, logico e ha senso che l'interfaccia System.Collections.ICollection eredita dall'interfaccia System.Collections.IEnumerable, perché teoricamente ogni raccolta è anche enumerabile e iterabile e ciò è teoricamente possibile esaminare tutti gli elementi e gli elementi in ogni collezione.

L'interfaccia System.Collections.ICollection rappresenta una raccolta dinamica finita che è modificabile, il che significa che gli elementi esistenti possono essere rimossi dalla raccolta e nuovi elementi possono essere aggiunti alla stessa raccolta.

Questo spiega perché l'interfaccia System.Collections.ICollection ha i metodi "Aggiungi" e "Rimuovi".

Poiché tali istanze dell'interfaccia System.Collections.ICollection sono raccolte finite, la parola "finita" implica che ogni raccolta di questa interfaccia contiene sempre un numero finito di elementi ed elementi.

La proprietà Count dell'interfaccia System.Collections.ICollection suppone di restituire questo numero.

L'interfaccia System.Collections.IEnumerable non ha questi metodi e proprietà dell'interfaccia System.Collections.ICollection, perché non ha alcun senso che System.Collections.IEnumerable abbia questi metodi e proprietà dell'interfaccia System.Collections.ICollection.

La logica dice anche che ogni istanza che è sia enumerabile che iterabile non è necessariamente una raccolta e non è necessariamente modificabile.

Quando dico mutevole, intendo che non penso immediatamente che puoi aggiungere o rimuovere qualcosa da qualcosa che è sia enumerabile che iterabile.

Se ho appena creato una sequenza finita di numeri primi, ad esempio, questa sequenza finita di numeri primi è davvero un'istanza di System.Collections.IEnumerabile interfaccia, perché ora posso esaminare tutti i numeri primi in questa sequenza finita in un singolo ciclo e fare qualunque cosa io voglia fare con ciascuno di essi, come stampare ciascuno di essi sulla finestra o sullo schermo della console, ma questa sequenza finita di numeri primi non è un'istanza dell'interfaccia System.Collections.ICollection, perché non ha senso aggiungere numeri compositi a questa sequenza finita di numeri primi.

Inoltre, nella prossima iterazione si desidera ottenere il prossimo numero primo più vicino più vicino al numero primo corrente nell'iterazione corrente, se così non si desidera rimuovere anche i numeri primi esistenti da questa sequenza finita di numeri primi.

Inoltre, probabilmente si desidera utilizzare, codificare e scrivere "rendimento restituito" nel metodo GetEnumerator dell'interfaccia System.Collections.IEnumerable per produrre i numeri primi e non allocare nulla sull'heap di memoria e quindi assegnare Garbage Collector (GC) a entrambi dislocare e liberare questa memoria dall'heap, poiché questo è ovviamente sia uno spreco di memoria del sistema operativo che una riduzione delle prestazioni.

L'allocazione dinamica della memoria e la deallocazione sull'heap devono essere eseguite quando si invocano i metodi e le proprietà dell'interfaccia System.Collections.ICollection, ma non quando si invocano i metodi e le proprietà dell'interfaccia System.Collections.IEnumerable (sebbene l'interfaccia System.Collections.IEnumerable abbia solo 1 metodo e 0 proprietà).

Secondo quanto affermato da altri in questa pagina Web Stack Overflow, l'interfaccia System.Collections.IList rappresenta semplicemente una raccolta ordinabile e questo spiega perché i metodi dell'interfaccia System.Collections.IList funzionano con gli indici in contrasto con quelli dell'interfaccia System.Collections.ICollection.

In breve l'interfaccia System.Collections.ICollection non implica che un'istanza di essa sia ordinabile, ma l'interfaccia System.Collections.IList lo implica.

Il set ordinato teoricamente è un caso speciale di set non ordinato.

Questo ha anche senso e spiega perché l'interfaccia System.Collections.IList eredita l'interfaccia System.Collections.ICollection.

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.