Warum ICollection und nicht IEnumerable oder List <T> für viele-viele / eins-viele-Beziehungen verwenden?


359

Ich sehe dies häufig in Tutorials mit Navigationseigenschaften als ICollection<T>.

Ist dies eine obligatorische Anforderung für das Entity Framework? Kann ich verwenden IEnumerable?

Was ist der Hauptzweck der Verwendung ICollectionanstelle von IEnumerableoder sogar List<T>?

Antworten:


440

Normalerweise hängt Ihre Auswahl davon ab, auf welche Methoden Sie zugreifen müssen. Im Allgemeinen - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx ) für eine Liste von Objekten, die nur durchlaufen werden müssen ICollection<>(MSDN: http: // msdn.microsoft.com/en-us/library/92t2ye13.aspx ) für eine Liste von Objekten, die durchlaufen und geändert werden müssen, List<>für eine Liste von Objekten, die durchlaufen, geändert, sortiert usw. werden müssen (siehe hier) Für eine vollständige Liste: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx ).

Unter einem genaueren Gesichtspunkt spielt das verzögerte Laden eine Rolle bei der Auswahl des Typs. Standardmäßig werden Navigationseigenschaften in Entity Framework mit Änderungsverfolgung geliefert und sind Proxys. Damit die dynamische Proxy als Navigationseigenschaft geschaffen werden, der virtuelle Typ muss implementieren ICollection.

Eine Navigationseigenschaft, die das "viele" Ende einer Beziehung darstellt, muss einen Typ zurückgeben, der ICollection implementiert, wobei T der Typ des Objekts am anderen Ende der Beziehung ist. - Anforderungen zum Erstellen von POCO Proxies MSDN

Weitere Informationen zum Definieren und Verwalten von Beziehungen MSDN


2
ListAlso , sollte das viel besser sein, ja?
Jan Carlo Viray

3
@ JanCarloViray - Ich neige dazu, Listviel zu verwenden. Obwohl es den größten Overhead hat, bietet es die meisten Funktionen.
Travis J

1
Listen werden mehr durch ihre Indexer definiert als durch die Fähigkeit, sie zu sortieren (ein ganzzahliger Indexer erleichtert das Sortieren von etwas, ist jedoch keine Voraussetzung).
Phoog

2
In Bezug auf Ihre Bearbeitung geht es bei der Beschränkung einer Eigenschaft auf einen Schnittstellentyp nicht um Speicher, sondern um Kapselung. Bedenken Sie: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };verwendet den gleichen Speicher wieprivate List<int> _integers = new List<int> { 1, 2, 3 };
Phoog

13
@TravisJ: List<T>hat eine GetEnumerator()von der Implementierung von getrennte Methode, IEnumerable<T>die einen veränderlichen Strukturtyp zurückgibt List<T>.Enumerator. In den meisten Kontexten bietet dieser Typ eine etwas bessere Leistung als ein eigenständiges Heap-Objekt. Compiler, die Enumeratoren vom Ententyp (wie C # und vb.net), können dies beim Generieren von foreachCode nutzen. Wenn die List<T>gegossen wird , IEnumrable<T>bevor die foreach, die IEnumerable<T>.GetEnumerator()zurückkehrt Methode ein Heap-Objekt zugewiesen, wodurch die Optimierung unmöglich.
Supercat

86

ICollection<T>wird verwendet, weil die IEnumerable<T>Benutzeroberfläche keine Möglichkeit bietet, Elemente hinzuzufügen, Elemente zu entfernen oder die Sammlung auf andere Weise zu ändern.


3
Was ist mit einem Vergleich mit List <T>?
Jan Carlo Viray

12
List<T>Geräte ICollection<T>.
Spender

Das nicht generische ICollectionElement erlaubt keine Möglichkeit, Elemente hinzuzufügen, ist jedoch eine nützliche Ergänzung, IEnumerable<T>da es ein CountMitglied bereitstellt, das normalerweise viel schneller ist als das Aufzählen aller Elemente . Beachten Sie, dass die Erweiterungsmethode schnell ist , wenn ein IList<Cat>oder ICollection<Cat>an Code übergeben wird, der ein erwartet IEnumerable<Animal>, Count()wenn es das nicht generische implementiert ICollection, aber nicht, wenn es nur die generischen Schnittstellen implementiert, da ein typisches ICollection<Cat>nicht implementiert wird ICollection<Animal>.
Supercat

58

Beantwortung Ihrer Frage zu List<T>:

List<T>ist eine Klasse; Die Angabe einer Schnittstelle ermöglicht eine flexiblere Implementierung. Eine bessere Frage ist "warum nicht IList<T>?"

Um diese Frage zu beantworten, überlegen Sie, was IList<T>zur ICollection<T>Ganzzahlindizierung beiträgt. Dies bedeutet, dass die Elemente eine beliebige Reihenfolge haben und unter Bezugnahme auf diese Reihenfolge abgerufen werden können. Dies ist in den meisten Fällen wahrscheinlich nicht sinnvoll, da Artikel in verschiedenen Kontexten wahrscheinlich unterschiedlich bestellt werden müssen.


21

Es gibt einige grundlegende Unterschiede zwischen ICollection und IEnumerable

  • IEnumerable - enthält nur die GetEnumerator-Methode zum Abrufen des Enumerators und ermöglicht das Schleifen
  • ICollection enthält zusätzliche Methoden: Hinzufügen, Entfernen, Enthält, Zählen, Kopieren
  • ICollection wird von IEnumerable geerbt
  • Mit ICollection können Sie die Sammlung mithilfe von Methoden wie Hinzufügen / Entfernen ändern. Sie haben nicht die Freiheit, dasselbe mit IEnumerable zu tun.

Einfaches Programm:

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

Ich erinnere mich so:

  1. IEnumerable verfügt über eine Methode GetEnumerator (), mit der die Werte in einer Sammlung gelesen, aber nicht beschrieben werden können. Der größte Teil der Komplexität der Verwendung des Enumerators wird für uns durch die für jede Anweisung in C # erledigt. IEnumerable hat eine Eigenschaft: Current, die das aktuelle Element zurückgibt.

  2. ICollection implementiert IEnumerable und fügt einige zusätzliche Eigenschaften hinzu, von denen Count am häufigsten verwendet wird. Die generische Version von ICollection implementiert die Methoden Add () und Remove ().

  3. IList implementiert sowohl IEnumerable als auch ICollection und fügt den Integer-Indizierungszugriff zu Elementen hinzu (was normalerweise nicht erforderlich ist, da die Bestellung in der Datenbank erfolgt).


4
Basierend auf dem, was Sie geschrieben haben, sind ICollection und IList gleich. Bitte fügen Sie hinzu, was zu IList hinzugefügt wird, das in ICollection nicht vorhanden ist.
Wetten

ICollection VS IList, IList-only-Schnittstelle in der System.Collection, die alle Funktionen von IEnumerable und ICollection sowie zusätzliche Funktionen enthält. IList verfügt über Methoden zum Einfügen und Entfernen. Beide Methoden akzeptieren den Index in ihrem Parameter. Es unterstützt also indexbasierte Operationen über die Sammlung.
E.Meir

7

Die Grundidee der Verwendung ICollectionbesteht darin, eine Schnittstelle für den schreibgeschützten Zugriff auf eine begrenzte Datenmenge bereitzustellen. Tatsächlich haben Sie eine ICollection.Count- Eigenschaft. IEnumerableist besser geeignet für eine Kette von Daten, in der Sie bis zu einem logischen Punkt, einer vom Verbraucher ausdrücklich angegebenen Bedingung oder bis zum Ende der Aufzählung lesen.


14
Bis das ICollectionschreibgeschützt ist, ICollection<T>ist es nicht.
Carl G

2

Navigationseigenschaften werden normalerweise als virtuell definiert, damit sie bestimmte Entity Framework-Funktionen wie z. B. verzögertes Laden nutzen können.

Wenn eine Navigationseigenschaft mehrere Entitäten enthalten kann (wie in Viele-zu-Viele- oder Eins-zu-Viele-Beziehungen), muss ihr Typ eine Liste sein, in der Einträge hinzugefügt, gelöscht und aktualisiert werden können, z. B. 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-anwendung


2

Was ich in der Vergangenheit getan habe, ist, meine inneren Klassensammlungen mit oder (falls statische Liste) zu deklarieren IList<Class>, je nachdem, ob ich in einer Methode in meinem Repository eine der folgenden Aktionen ausführen muss oder nicht : Aufzählen, Sortieren / Ordnen oder Ändern . Wenn ich nur Objekte aufzählen (und möglicherweise sortieren) muss, erstelle ich eine temporäre Datei, um mit der Sammlung innerhalb einer IEnumerable-Methode zu arbeiten. Ich denke, diese Praxis wäre nur dann effektiv, wenn die Sammlung relativ klein ist, aber es kann allgemein eine gute Praxis sein, idk. Bitte korrigieren Sie mich, wenn es Beweise dafür gibt, warum dies keine gute Praxis wäre.ICollection<Class>IEnumerable<Class>List<Class>


0

Versuchen wir, mit / durch Logik über den Tellerrand hinaus zu denken und diese drei Schnittstellen in Ihrer Frage klar zu verstehen:

Wenn die Klasse einer Instanz die System.Collection.IEnumerable-Schnittstelle implementiert, können wir in einfachen Worten sagen, dass diese Instanz sowohl aufzählbar als auch iterierbar ist, was bedeutet, dass diese Instanz in einer einzelnen Schleife irgendwie zulässt, dass sie geht / get / pass / Durchlaufen / Durchlaufen aller Elemente und Elemente, die diese Instanz enthält.

Dies bedeutet, dass auf diese Weise auch alle in dieser Instanz enthaltenen Elemente und Elemente aufgelistet werden können.

Jede Klasse, die die System.Collection.IEnumerable-Schnittstelle implementiert, implementiert auch die GetEnumerator-Methode, die keine Argumente akzeptiert und eine System.Collections.IEnumerator-Instanz zurückgibt.

Instanzen der System.Collections.IEnumerator-Schnittstelle verhalten sich C ++ - Iteratoren sehr ähnlich.

Wenn die Klasse einer Instanz die System.Collection.ICollection-Schnittstelle implementiert, können wir in einfachen Worten sagen, dass diese Instanz eine Sammlung von Dingen ist.

Die generische Version dieser Schnittstelle, dh System.Collection.Generic.ICollection, ist informativer, da diese generische Schnittstelle explizit angibt, um welche Art von Dingen es sich in der Sammlung handelt.

Dies ist alles vernünftig, rational, logisch und macht Sinn, dass die System.Collections.ICollection-Schnittstelle von der System.Collections.IEnumerable-Schnittstelle erbt, da theoretisch jede Sammlung sowohl aufzählbar als auch iterierbar ist und dies theoretisch möglich ist, alle Elemente und Elemente zu durchlaufen in jeder Sammlung.

Die System.Collections.ICollection-Schnittstelle stellt eine endliche dynamische Sammlung dar, die geändert werden kann. Dies bedeutet, dass vorhandene Elemente aus der Sammlung entfernt und neue Elemente derselben Sammlung hinzugefügt werden können.

Dies erklärt, warum die System.Collections.ICollection-Schnittstelle über die Methoden "Hinzufügen" und "Entfernen" verfügt.

Da diese Instanzen der System.Collections.ICollection-Schnittstelle endliche Sammlungen sind, impliziert das Wort "endlich", dass jede Sammlung dieser Schnittstelle immer eine endliche Anzahl von Elementen und Elementen enthält.

Die Eigenschaft Count of System.Collections.ICollection-Schnittstelle setzt voraus, dass diese Nummer zurückgegeben wird.

Die System.Collections.IEnumerable-Schnittstelle verfügt nicht über diese Methoden und Eigenschaften wie die System.Collections.ICollection-Schnittstelle, da es keinen Sinn macht, dass System.Collections.IEnumerable über diese Methoden und Eigenschaften der System.Collections.ICollection-Schnittstelle verfügt.

Die Logik besagt auch, dass jede Instanz, die sowohl aufzählbar als auch iterierbar ist, nicht unbedingt eine Sammlung ist und nicht unbedingt geändert werden kann.

Wenn ich veränderbar sage, meine ich, dass Sie nicht sofort denken, dass Sie etwas hinzufügen oder entfernen können, das sowohl aufzählbar als auch iterierbar ist.

Wenn ich zum Beispiel nur eine endliche Folge von Primzahlen erstellt habe, ist diese endliche Folge von Primzahlen tatsächlich eine Instanz der System.Collections.IEnumerable-Schnittstelle, da ich jetzt alle Primzahlen in dieser endlichen Folge in einer einzigen Schleife durchgehen kann und mache, was ich mit jedem von ihnen machen will, wie jeden von ihnen auf das Konsolenfenster oder den Bildschirm zu drucken, aber diese endliche Folge von Primzahlen ist keine Instanz der System.Collections.ICollection-Schnittstelle, da dies für keinen Sinn macht Fügen Sie dieser endlichen Folge von Primzahlen zusammengesetzte Zahlen hinzu.

Außerdem möchten Sie in der nächsten Iteration die nächstnächere größere Primzahl zur aktuellen Primzahl in der aktuellen Iteration erhalten. Wenn ja, möchten Sie auch keine vorhandenen Primzahlen aus dieser endlichen Folge von Primzahlen entfernen.

Außerdem möchten Sie wahrscheinlich "Yield Return" in der GetEnumerator-Methode der System.Collections.IEnumerable-Schnittstelle verwenden, codieren und schreiben, um die Primzahlen zu erzeugen und nichts auf dem Speicherheap zuzuweisen, und dann den Garbage Collector (GC) beiden zuweisen Geben Sie die Zuordnung auf und geben Sie diesen Speicher vom Heap frei, da dies offensichtlich sowohl eine Verschwendung des Betriebssystemspeichers als auch eine Verringerung der Leistung darstellt.

Die dynamische Speicherzuweisung und Freigabe auf dem Heap sollte beim Aufrufen der Methoden und Eigenschaften der System.Collections.ICollection-Schnittstelle erfolgen, nicht jedoch beim Aufrufen der Methoden und Eigenschaften der System.Collections.IEnumerable-Schnittstelle (obwohl die System.Collections.IEnumerable-Schnittstelle nur über diese verfügt 1 Methode und 0 Eigenschaften).

Gemäß den Aussagen anderer auf dieser Stack Overflow-Webseite stellt die System.Collections.IList-Schnittstelle lediglich eine bestellbare Sammlung dar. Dies erklärt, warum die Methoden der System.Collections.IList-Schnittstelle im Gegensatz zu denen der System.Collections.ICollection-Schnittstelle mit Indizes arbeiten.

Kurz gesagt, die System.Collections.ICollection-Schnittstelle impliziert nicht, dass eine Instanz davon bestellbar ist, aber die System.Collections.IList-Schnittstelle impliziert dies.

Theoretisch geordnete Menge ist Sonderfall einer ungeordneten Menge.

Dies ist auch sinnvoll und erklärt, warum die System.Collections.IList-Schnittstelle die System.Collections.ICollection-Schnittstelle erbt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.