Was ist der Unterschied zwischen Liste (von T) und Sammlung (von T)?

92

Ich habe gesehen, wie sie auf die gleiche Weise verwendet wurden, und ich mache mir Sorgen, dass ich einen Weg im Design beschreiten werde, der irreversibel ist, wenn ich das nicht besser verstehe. Außerdem verwende ich .NET.

Anthony Potts
quelle

Antworten:

50

Collection<T>ist ein anpassbarer Wrapper IList<T>. Es IList<T>ist zwar nicht versiegelt, bietet jedoch keine Anpassungspunkte. Collection<T>Die Methoden von sind standardmäßig an die Standardmethoden delegiert IList<T>, können jedoch leicht überschrieben werden, um das zu tun, was Sie wollen. Es ist auch möglich, Ereignisse innerhalb eines zu verkabeln Collection<T>, von dem ich nicht glaube, dass es mit einem IList möglich ist.

Kurz gesagt, es ist viel einfacher, es nachträglich zu erweitern, was möglicherweise viel weniger Refactoring bedeuten könnte.

Adam Lassek
quelle
@Marc Gravell, @Adam Lassek: Können wir nicht dasselbe mit einer Liste tun, indem wir die InsertItem (...) -Methode mit einem öffentlichen void new InsertItem (...) ausblenden und dann die base.InsertItem (.. .) von innen ? Es würde immer noch nicht den Vertrag brechen. (Der Name ist 'Einfügen' in Liste, aber trotzdem). Was ist die große Sache, wenn man sich an Sammlungen <T> hält?
DeeStackOverflow
4
@DeeStackOverflow - weil Methode versteckt wird nicht von jedem Code verwendet werden , die eine andere API verwendet - also alles , was sieht für IList, IList<T>, List<T>usw. Kurz gesagt, Sie haben keine Ahnung, ob es aufgerufen wird. Polymorphismus behebt dies.
Marc Gravell
@AdamLassek: Möglicherweise möchten Sie in Ihrer Antwort ObservableCollection<T>ein Beispiel hinzufügen, bei dem Methoden überschrieben werden, um über Änderungen zu informieren.
Kiran Challa
82

In C # gibt es drei Konzepte zur Darstellung einer Tasche von Objekten. In der Reihenfolge zunehmender Funktionen sind dies:

  • Aufzählbar - ungeordnet, nicht veränderbar
  • Sammlung - kann Elemente hinzufügen / entfernen
  • Liste - Ermöglicht es Artikeln, eine Reihenfolge zu haben (Zugriff auf und Entfernen über den Index)

Enumerable hat keine Reihenfolge. Sie können keine Elemente zum Set hinzufügen oder daraus entfernen. Sie können nicht einmal eine Anzahl von Elementen im Set erhalten. Sie können strikt nacheinander auf jedes Element im Set zugreifen.

Die Sammlung ist ein modifizierbarer Satz. Sie können Objekte zum Set hinzufügen und daraus entfernen. Sie können auch die Anzahl der Elemente im Set abrufen. Aber es gibt immer noch keine Reihenfolge, und weil es keine Reihenfolge gibt: keine Möglichkeit, auf einen Artikel nach Index zuzugreifen, noch gibt es eine Möglichkeit, ihn zu sortieren.

Liste ist eine geordnete Menge von Objekten. Sie können die Liste sortieren, auf Elemente nach Index zugreifen und Elemente nach Index entfernen.

Wenn man sich die Schnittstellen für diese ansieht, bauen sie tatsächlich aufeinander auf:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

Wenn Sie Variablen oder Methodenparameter deklarieren, sollten Sie diese verwenden

  • IEnumerable
  • ICollection
  • IList

basierend auf konzeptionell müssen Sie mit der Menge der Objekte tun.

Wenn Sie nur in der Lage sein müssen, mit jedem Objekt in einer Liste etwas zu tun, brauchen Sie nur IEnumerable:

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

Sie kümmern sich nicht , wenn die Nutzer in einem gehalten werden List<T>, Collection<T>, Array<T>oder irgendetwas anderes. Sie brauchen nur die IEnumerable<T>Schnittstelle.

Wenn Sie in der Lage sein müssen, die Elemente in einem Satz hinzuzufügen, zu entfernen oder zu zählen, verwenden Sie eine Sammlung :

ICollection<User> users = new Collection<User>();
users.Add(new User());

Wenn Sie sich für eine Sortierreihenfolge interessieren und die Reihenfolge korrekt sein muss, verwenden Sie eine Liste :

IList<User> users = FetchUsers(db);

In Diagrammform:

| 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        |

Das List<T>und Collection<T>in System.Collections.Genericsind zwei Klassen, die diese Schnittstellen implementieren. aber sie sind nicht die einzigen Klassen:

  • ConcurrentBag<T>ist eine bestellte Tüte mit Gegenständen ( IEnumerable<T>)
  • LinkedList<T>ist eine Tasche, in der Sie nicht über index ( ICollection) auf Elemente zugreifen dürfen ; Sie können jedoch beliebig Elemente zur Sammlung hinzufügen und daraus entfernen
  • SynchronizedCollection<T> in einer geordneten Sammlung, in der Sie Elemente nach Index hinzufügen / entfernen können

So können Sie leicht ändern:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

tl; dr

  • Aufzählbar - Zugriff auf Elemente, ungeordnet, nicht veränderbar
  • Sammlung - kann geändert werden (hinzufügen, löschen, zählen)
  • Liste - kann über Index zugreifen

Wählen Sie das gewünschte Konzept und verwenden Sie die passende Klasse.

Ian Boyd
quelle
11
Das OP hat nach den konkreten Typen gefragt, und Sie haben die Schnittstellen verglichen. Der konkrete Typ Collection <T> implementiert IList <T> und kann über Indexfunktionen zugreifen.
JJS
2
Die Antwort ist gut, aber von der Frage abweichend. Kann nicht zu Ihrer Antwort für die Klassen Collection <T> und List <T> passen. Ich meine, wenn ich versuche, Ihren Standpunkt zu bestätigen, rechtfertigen sie dies einfach nicht. Für eine allgemeine Antwort haben Sie möglicherweise Recht, dass die Sammlung nicht geordnet ist, sodass keine Indizierung erfolgt, sondern die Liste, damit das Einfügen in einen bestimmten Index möglich ist.
Kylo Ren
Was wäre, wenn ich Funktionen von ICollection <T> haben und auch lösen und Möglichkeiten finden würde?
2
Wenn die Liste geordnet ist und die Sammlung ordentlich ist, wäre dies ein großer funktionaler Unterschied, um einen neuen Lernenden (wie mich) leicht bei der Auswahl zu unterstützen. Aber warte, warum hat eine Sammlung keine Bestellung? Es bietet die Methoden IndexOf () und RemoveAt () , also ist es geordnet, nicht wahr ? Habe ich hier etwas verpasst?
RayLuo
1
@ RayLuo Ich beziehe mich speziell auf ICollection<T>und IList<T>. Unterschiedliche konkrete Implementierungen können sich unterschiedlich verhalten. Wenn Sie beispielsweise List<T>über die IEnumerable<T>Benutzeroberfläche auf a zugreifen , können Sie der Liste keine Elemente hinzufügen, entfernen, sortieren oder zählen.
Ian Boyd
43

List<T>ist für den internen Gebrauch innerhalb des Anwendungscodes vorgesehen. Sie sollten vermeiden, öffentliche APIs zu schreiben, die akzeptieren oder zurückgeben List<T>(verwenden Sie stattdessen eine Oberklasse oder eine Sammlungsschnittstelle).

Collection<T> dient als Basisklasse für benutzerdefinierte Sammlungen (obwohl sie direkt verwendet werden kann).

Erwägen Sie die Verwendung Collection<T>in Ihrem Code, es sei denn List<T>, Sie benötigen bestimmte Funktionen .

Die oben genannten sind nur Empfehlungen.

[Adaptiert aus: Framework Design Guidelines, Second Edition]

Arnold Zokas
quelle
Es ist erwähnenswert , dass Arten der Feststellung , die Verwendung jede Art von veränderbaren Objekten kapseln ihren eigenen Staat sollte Rückkehr Objekte dieser Art vermeiden , es sei denn entweder die betreffenden Objekte ein Mittel der Benachrichtigung ihre Besitzer , wenn sie mutiert sind, oder der Name des Verfahrens wird die Rückkehr Objekt impliziert eindeutig, dass es eine neue Instanz zurückgibt. Beachten Sie, dass beispielsweise Dictionary<string, List<string>>die Rückkehr von a List<string>in Ordnung ist, da der Status des Wörterbuchs nur die Identitäten der darin enthaltenen Listen und nicht deren Inhalt enthält.
Supercat
37

List<T>ist ein sehr häufig gesehen Behälter, weil es so sehr vielseitig (mit vielen praktischen Methoden wie ist Sort, Findusw.) - aber keine Erweiterungspunkte hat , wenn Sie das Verhalten (Prüfpunkte auf dem Einsatz, zum Beispiel) außer Kraft setzen mögen.

Collection<T>ist ein Wrapper um any IList<T>(standardmäßig List<T>) - es hat die Erweiterungspunkte ( virtualMethoden), aber nicht so viele Unterstützungsmethoden wie Find. Aufgrund der Indirektion ist es etwas langsamer als List<T>, aber nicht viel.

Mit LINQ, die zusätzlichen Methoden in List<T>weniger wichtig geworden, da LINQ-to-Objects neigt , sie trotzdem zu schaffen , ... zum Beispiel First(pred), OrderBy(...)usw.

Marc Gravell
quelle
6
In Collection <T> fehlt die Methode foreach, selbst in Linq-to-Objects.
Tuinstoel
7
@ Tuinstoel - aber es ist trivial hinzuzufügen.
Marc Gravell
12

Liste ist schneller.

Mach zum Beispiel

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());


}

auf meiner Maschine List<>ist fast doppelt so schnell.

Bearbeiten

Ich kann nicht verstehen, warum die Leute dies ablehnen. Sowohl auf meiner Arbeitsmaschine als auch auf meiner Heimmaschine ist der Listencode <> 80% schneller.

tuinstoel
quelle
1
Wie geht es schneller? Sieh nach oben? Einfügen? Entfernung? Suche? Warum ist es schneller?
Doug T.
17
Liste ist weniger Buchstaben zu
schreiben
1
Sammlung hat weniger Methoden. Deshalb ist es schneller. QED. (Scherz, ich
Ray
2
Versuchte es auf meinem Computer und Liste ist etwa 20% schneller. Würde mich für eine Diskussion interessieren, warum dies sein könnte. Vielleicht ist die Liste besser mit der Zuweisung von Speicher.
Ray
10
Die Methoden von List sind nicht vererbbar, daher wird nicht überprüft, ob sie vererbt wurden. Die Methoden der Sammlung sind vererbbar. Der Vorteil ist, dass Sie Collection als Basisklasse verwenden können, um eine benutzerdefinierte Collection zu erben und zu erstellen.
Richard Gadsden
11

Liste stellt eine Sammlung dar, bei der die Reihenfolge der Elemente wichtig ist. Es werden auch Methoden wie Sortieren und Suchen unterstützt. Die Sammlung ist eine allgemeinere Datenstruktur, die weniger Annahmen über die Daten macht und auch weniger Methoden zur Bearbeitung unterstützt. Wenn Sie eine benutzerdefinierte Datenstruktur verfügbar machen möchten, sollten Sie die Sammlung wahrscheinlich erweitern. Wenn Sie Daten bearbeiten müssen, ohne die Datenstruktur verfügbar zu machen, ist eine Liste wahrscheinlich der bequemere Weg.

Manu
quelle
4

Dies ist eine dieser Fragen der Graduiertenschule. Eine Sammlung von T ist eine Art Zusammenfassung; Möglicherweise gibt es eine Standardimplementierung (ich bin kein .net / c # -Typ), aber eine Sammlung verfügt über grundlegende Vorgänge wie Hinzufügen, Entfernen, Iterieren usw.

Die Liste von T impliziert einige Besonderheiten dieser Operationen: Hinzufügen sollte eine konstante Zeit in Anspruch nehmen, Entfernen sollte eine Zeit benötigen, die proportional zur Anzahl der Elemente ist, getfirst sollte eine konsistente Zeit sein. Im Allgemeinen ist eine Liste eine Art Sammlung, aber eine Sammlung ist nicht unbedingt eine Art Liste.

Charlie Martin
quelle
4

Hanselman spricht : " Collection<T>Sieht aus wie eine Liste und hat sogar eine List<T>interne. JEDE einzelne Methode wird an die interne delegiert List<T>. Sie enthält eine geschützte Eigenschaft, die die verfügbar macht List<T>."

BEARBEITEN: Collection<T>existiert nicht in System.Generic.Collections .NET 3.5. Wenn Sie von .NET 2.0 auf 3.5 migrieren, müssen Sie Code ändern, wenn Sie viele Collection<T>Objekte verwenden, es sei denn, mir fehlt etwas Offensichtliches ...

BEARBEITEN 2: Collection<T>befindet sich jetzt im System.Collections.ObjectModel-Namespace in .NET 3.5. In der Hilfedatei heißt es:

"Der System.Collections.ObjectModel-Namespace enthält Klassen, die als Sammlungen im Objektmodell einer wiederverwendbaren Bibliothek verwendet werden können. Verwenden Sie diese Klassen, wenn Eigenschaften oder Methoden Sammlungen zurückgeben."

Tad Donaghe
quelle
4

Alle diese Schnittstellen erben von IEnumerable, von denen Sie sicherstellen sollten, dass Sie sie verstehen. Mit dieser Schnittstelle können Sie die Klasse grundsätzlich in einer foreach-Anweisung (in C #) verwenden.

  • ICollectionist die grundlegendste der von Ihnen aufgelisteten Schnittstellen. Es ist eine aufzählbare Schnittstelle, die a unterstützt Countund das war's auch schon.
  • IListist alles, was ICollectionist, aber es unterstützt auch das Hinzufügen und Entfernen von Elementen, das Abrufen von Elementen nach Index usw. Es ist die am häufigsten verwendete Schnittstelle für "Listen von Objekten", was vage ist, wie ich weiß.
  • IQueryableist eine aufzählbare Schnittstelle, die LINQ unterstützt. Sie können jederzeit eine IQueryableaus einer IList erstellen und LINQ für Objekte verwenden. Sie werden jedoch auch IQueryablefür die verzögerte Ausführung von SQL-Anweisungen in LINQ für SQL und LINQ für Entitäten verwendet.
  • IDictionaryist ein anderes Tier in dem Sinne, dass es eine Zuordnung eindeutiger Schlüssel zu Werten ist. Es ist auch insofern aufzählbar, als Sie die Schlüssel / Wert-Paare auflisten können, aber ansonsten dient es einem anderen Zweck als die anderen, die Sie aufgelistet haben
Raj Gupta
quelle
ICollection unterstützt das Hinzufügen / Entfernen / Clearing: msdn.microsoft.com/en-us/library/...
Amnesie
4

Laut MSDN ist List (Of T) .Add "eine O (n) -Operation" (wenn "Capacity" überschritten wird), während Collection (Of T) .Add immer "eine O (1) -Operation " ist. Das wäre verständlich, wenn List mithilfe eines Arrays implementiert und eine verknüpfte Liste gesammelt würde. Wenn dies jedoch der Fall wäre, würde man erwarten, dass Collection (Of T) .Item "eine O (n) -Operation" ist. Aber - es ist - nicht !?! Collection (Of T) .Item ist "eine O (1) -Operation", genau wie List (Of T) .Item.

Darüber hinaus zeigt "tuinstoel" 's "29. Dezember 08 um 22:31" Beitrag oben Behauptungen Geschwindigkeitstests zeigen Liste (von T). Hinzufügen, um schneller zu sein als Sammlung (von T). Hinzufügen, mit denen ich reproduziert habe Long's und String's. Obwohl ich laut MSDN nur ~ 33% schneller geworden bin als seine behaupteten 80%, hätte es das Gegenteil sein sollen und zu "n" Zeiten!?!

Tom
quelle
3

Beide implementieren dieselben Schnittstellen, sodass sie sich gleich verhalten. Vielleicht werden sie intern anders implementiert, aber dies müsste getestet werden.

Die einzigen wirklichen Unterschiede, die ich sehe, sind die Namespaces und die Tatsache, dass Collection<T>sie mit ComVisibleAttribute(false)COM-Code nicht verwendet werden können.

OwenP
quelle
Sie implementieren verschiedene Schnittstellen - List <T> implementiert IList <T>, Collection <T> nicht.
Bevan
@Bevan versuchen Sie es in c #, beide implementieren die gleichen Schnittstellen
Kylo Ren
1
Das ist eine interessante Veränderung @KyloRen - sie haben jetzt beide den gleichen Satz von Schnittstellen implementieren; Dies war 2008 nicht der Fall.
Bevan
1
@Bevan interessant. Ich bin mir nicht sicher, was der Grund für zwei verschiedene Klassen war, eine mit nur einigen zusätzlichen Methoden.
Kylo Ren
3

Zusätzlich zu anderen Antworten habe ich einen schnellen Überblick über allgemeine Listen- und Erfassungsfunktionen zusammengestellt. Sammlung ist begrenzte Teilmenge der Liste:

* = vorhanden 
o = teilweise vorhanden

Property / Method - Sammlung < T > Liste < 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()                        *
miroxlav
quelle