Unterschied zwischen verschiedenen generischen Sammlungsschnittstellen in C #


11

Ich spiele seit einiger Zeit mit der Entwicklung von C # für Windows und ASP.net MVC. In einigen Bereichen bin ich jedoch noch unklar. Ich versuche, den grundlegenden Unterschied zwischen und Leistungsproblemen bei der Verwendung und dem Austausch ähnlicher Arten von generischen Sammlungsschnittstellen zu verstehen .

Was ist der grundlegende Unterschied zwischen IEnumerable<T>, ICollection<T>, List<T>(Class)?

Ich scheine sie zu verwenden und auszutauschen, ohne Probleme in meinen Anwendungen zu sehen. Gibt es auch ähnliche generische Sammlungen wie diese, die mit diesen drei ausgetauscht werden können?


2
es gibt auch IList <T>
jk.

Antworten:


19

List <T> ist eine Klasse und implementiert sowohl die ICollection <T> - als auch die IEnumerable <T> -Schnittstelle. Außerdem erweitert ICollection <T> die IEnumerable <T> -Schnittstelle. Sie sind nicht austauschbar, zumindest nicht unter allen Gesichtspunkten.

Wenn Sie über eine Liste <T> verfügen, wird garantiert, dass dieses Objekt Methoden und Eigenschaften implementiert, die von der Schnittstelle ICollection <T> und IEnumerable <T> implementiert werden müssen. Der Compiler weiß es und Sie dürfen sie implizit entweder in eine ICollection <T> oder eine IEnumerable <T> "down". Wenn Sie jedoch über eine ICollection <T> verfügen, müssen Sie in Ihrem Code zunächst explizit überprüfen, ob es sich um eine Liste <T> oder etwas anderes handelt, möglicherweise um ein Wörterbuch <T> (wobei T ein KeyValuePair ist ), bevor Sie es in das übertragen, was Sie möchten Verlangen.

Sie wissen, dass ICollection IEnumerable erweitert, sodass Sie es in eine IEnumerable umwandeln können. Wenn Sie jedoch nur eine IEnumerable haben, kann Ihnen nicht garantiert werden, dass es sich um eine Liste handelt. Es mag sein, aber es könnte etwas anderes sein. Sie sollten eine ungültige Besetzungsausnahme erwarten, wenn Sie beispielsweise versuchen, eine Liste <T> in ein Wörterbuch <T> umzuwandeln.

Sie sind also nicht "austauschbar".

Es gibt auch viele generische Schnittstellen. Sehen Sie sich an, was Sie im System.Collections.Generic- Namespace finden.

Bearbeiten: In Bezug auf Ihren Kommentar gibt es absolut keine Leistungseinbußen, wenn Sie List <T> oder eine der implementierten Schnittstellen verwenden. Sie müssen noch ein neues Objekt erstellen. Überprüfen Sie den folgenden Code:

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

list , myColl und myEnum zeigen alle auf dasselbe Objekt. Unabhängig davon, ob Sie es als Liste, ICollection oder IEnumerable deklarieren, muss das Programm weiterhin eine Liste erstellen. Ich hätte das schreiben können:

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

myColl ist zur Laufzeit noch eine Liste.

Dies ist jedoch der wichtigste Punkt. Um die Kopplung zu verringern und die Wartbarkeit zu erhöhen, sollten Sie Ihre Variablen und Methodenparameter immer mit dem kleinstmöglichen Nenner deklarieren, unabhängig davon, ob es sich um eine Schnittstelle, eine abstrakte oder eine konkrete Klasse handelt.

Stellen Sie sich vor, die "PerformOperation" -Methode muss nur Elemente auflisten, einige Arbeiten ausführen und beenden. In diesem Fall benötigen Sie nicht die hundert weiteren in Liste <T> verfügbaren Methoden, sondern nur die in IEnumerable <T verfügbaren >, daher sollte folgendes gelten:

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

Auf diese Weise wissen Sie und andere Entwickler, dass dieser Methode jedes Objekt einer Klasse zugewiesen werden kann, die die IEnumerable <T> -Schnittstelle implementiert. Es kann sich um eine Liste, ein Wörterbuch oder eine benutzerdefinierte Sammlungsklasse handeln, die ein anderer Entwickler geschrieben hat.

Wenn Sie im Gegenteil angeben, dass Sie explizit eine konkrete Liste <T> benötigen (und obwohl dies im wirklichen Leben selten der Fall ist, kann dies dennoch vorkommen), wissen Sie und andere Entwickler, dass es sich entweder um eine Liste oder eine andere konkrete Klasse handeln muss, die diese erbt aus der Liste.


Zunächst einmal vielen Dank. Jetzt geht es darum, wie man entscheidet, welche man verwendet. Da List <T> beide Schnittstellen implementiert, sollten Sie es nicht immer an jedem Ort verwenden, an dem IEnumerable oder ICollection erforderlich sind. Wird sich die Verwendung einer Liste immer auf die Leistung auswirken? Bitte bearbeiten Sie Ihre Antwort, um auf diese Bedenken zu antworten
Pankaj Upadhyay

Ich habe bearbeitet, um Ihre Leistungsfragen zu beantworten
Jalayn

+1, aber ich möchte hinzufügen, dass Sie in den seltenen Fällen, in denen Sie tatsächlich eine Liste an eine Methode übergeben müssen, diese IListanstelle Listder Methodendeklaration verwenden sollten.
Konamiman

@Konamiman - Hängt davon ab, ob Sie List<>bestimmte Funktionen benötigen , wie z .AddRange(). Das IList<>macht das nicht sichtbar.
Bobson

6

Schauen Sie sich die MSDN-Seiten für ICollection und IEnumerable an .

In sehr abstrakten Begriffen stelle ich mir diese Typen so vor.

Ein IEnumerable ist alles, was aufgezählt werden kann - das heißt, es wird wiederholt. Es bedeutet nicht unbedingt eine "Sammlung"; Ein IQueryable implementiert beispielsweise IEnumerable und ist keine Sammlung, sondern kann abgefragt werden, um Objekte zurückzugeben. Um IEnumerable zu implementieren, muss ein Objekt nur in der Lage sein, ein Objekt zurückzugeben, wenn es abgefragt wird. Ich könnte sagen, dass ich eine Aufzählung von Aufgaben habe, die ich heute erledigen werde (es ist keine Liste, weil ich sie nicht aufgeschrieben oder formuliert habe, aber ich könnte Ihnen sagen, was ich jetzt tun werde, und Wenn Sie 'und dann?' gefragt haben, kann ich Ihnen die folgende Aufgabe mitteilen.

Eine ICollection ist konkreter als eine IEnumerable. Ein wesentlicher Unterschied besteht darin, dass eine Sammlung weiß, wie viele Elemente sie enthält. Um herauszufinden, wie viele Elemente sich in einer Aufzählung befinden, durchlaufen Sie diese effektiv und zählen sie:

Ich: Leute, wie viele Gegenstände haben Sie jeweils in sich?

Aufzählbar: Ich weiß es nicht wirklich. Nun, hier ist ein Punkt. Ich habe noch einen, also sind das zwei. Und noch einer, also drei ... und noch einer ... ok, das sind 2382. Keine Gegenstände mehr, also habe ich 2382. Frag mich nicht noch einmal, weil ich sie alle noch einmal durchgehen muss.

Sammlung: Ich habe 2382 Artikel. Das weiß ich schon.

Eine Sammlung ist normalerweise etwas, das bereits weiß, wo sich alle Elemente befinden, und sie nicht suchen oder generieren muss, wenn Sie danach fragen. Es ist mehr ... konkret als eine Aufzählung.

Meiner Meinung nach ist der Unterschied zwischen einer Aufzählung und einer Sammlung viel größer als der Unterschied zwischen einer Sammlung und einer Liste. Tatsächlich fällt es mir schwer, an einen praktischen Unterschied zwischen einer Sammlung und einer Liste zu denken, aber ich glaube, dass List bessere Methoden für die Suche und Bestellung bietet.

Andere Arten der Sammlung umfassen Queueund Stack, sowie Dictionary.

Die Namen dieser Typen sind sehr nützlich - Sie können sich eine Warteschlange und einen Stapel als ihre realen Gegenstücke vorstellen und die Unterschiede berücksichtigen, die Sie möglicherweise zu einer Liste haben.


"Ich habe Mühe, mir einen praktischen Unterschied zwischen einer Sammlung und einer Liste vorzustellen" ... Später in Ihrer Antwort beantworten Sie dies selbst. A Listist eine ICollection, aber eine ICollectionist nicht immer ein List( Queue, Stack, Dictionary, ...)
Steven Jeuris

@Steven Es ist eine sehr weitläufige Antwort. Ich stimme zu, dass dies ein wichtiger Unterschied ist, aber ich würde es nicht als praktischen Unterschied bezeichnen. Was bedeutet das für den Benutzer?
Kirk Broadhurst

Das ist leicht! :) Queue<int> queue = (Queue<int>)list;wird ein InvalidCastExceptionWann werfen listist kein Queue<int>. Der Unterschied zwischen Warteschlange und Liste ist für diese Frage nicht relevant.
Steven Jeuris

Ist nicht der kritische Aspekt von IEnumerable, dass es die aktuellen und nächsten Elemente zurückgeben kann - Sie spielen irgendwie darauf an, sagen es aber nicht explizit. Im Wesentlichen kann etwas, das IEnumerable alleine implementiert, bei Abfrage kein beliebiges Element seiner Mitglieder zurückgeben - nur das aktuelle und das nächste.
Cori

@cori Das ist eine sehr prägnante Art, viel klarer als meine Antwort.
Kirk Broadhurst

-1

IQueryable:

Die Abfrage wird erst ausgeführt, um die Elemente wirklich zu durchlaufen, möglicherweise durch Ausführen einer .ToList ()

IEnumerable:

Nur-Vorwärts-Liste der Elemente. Sie können nicht zu "Punkt 4" gelangen, ohne die Punkte 0-3 zu übergeben. schreibgeschützte Liste, die Sie nicht hinzufügen oder daraus entfernen können. Möglicherweise wird die verzögerte Ausführung weiterhin verwendet.

IList:

Der zufällige Zugriff auf die vollständige Liste vollständig im Speicher unterstützt das Hinzufügen und Entfernen

ICollection:

Ist zwischen IEnumerable und IList. Was "am besten" ist, hängt von Ihren Anforderungen ab. Normalerweise ist eine IEnumerable jedoch "gut genug", wenn Sie nur Elemente anzeigen möchten. Verwenden Sie zumindest immer die generische Variante.


Diese Antwort scheint nichts Wertvolles über das hinzuzufügen, was bereits in früheren Antworten gepostet wurde
Mücke

Es ist nur ein einfaches Konzept über alle
Zia Qammar
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.