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.
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.
Antworten:
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.
IList
, IList<T>
, List<T>
usw. Kurz gesagt, Sie haben keine Ahnung, ob es aufgerufen wird. Polymorphismus behebt dies.
ObservableCollection<T>
ein Beispiel hinzufügen, bei dem Methoden überschrieben werden, um über Änderungen zu informieren.
In C # gibt es drei Konzepte zur Darstellung einer Tasche von Objekten. In der Reihenfolge zunehmender Funktionen sind dies:
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
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.Generic
sind 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 entfernenSynchronizedCollection<T>
in einer geordneten Sammlung, in der Sie Elemente nach Index hinzufügen / entfernen könnenSo können Sie leicht ändern:
IEnumerable<User> users = new SynchronizedCollection<User>();
SaveEveryUser(users);
Wählen Sie das gewünschte Konzept und verwenden Sie die passende Klasse.
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.
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]
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.
List<T>
ist ein sehr häufig gesehen Behälter, weil es so sehr vielseitig (mit vielen praktischen Methoden wie ist Sort
, Find
usw.) - 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 ( virtual
Methoden), 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.
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.
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.
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.
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."
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.
ICollection
ist die grundlegendste der von Ihnen aufgelisteten Schnittstellen. Es ist eine aufzählbare Schnittstelle, die a unterstützt Count
und das war's auch schon.IList
ist alles, was ICollection
ist, 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ß.IQueryable
ist eine aufzählbare Schnittstelle, die LINQ unterstützt. Sie können jederzeit eine IQueryable
aus einer IList erstellen und LINQ für Objekte verwenden. Sie werden jedoch auch IQueryable
für die verzögerte Ausführung von SQL-Anweisungen in LINQ für SQL und LINQ für Entitäten verwendet.IDictionary
ist 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 habenLaut 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!?!
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.
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() *