Um den "Warum" -Teil der Frage zu beantworten, warum nicht List<T>
, sind die Gründe zukunftssicher und API-Einfachheit.
Zukunftssicher
List<T>
ist nicht so konzipiert, dass es durch Unterklassen leicht erweiterbar ist; Es ist so konzipiert, dass es für interne Implementierungen schnell ist. Sie werden bemerken , die Methoden auf nicht virtuell sind und so nicht außer Kraft gesetzt werden kann, und es gibt keine Haken in seine Add
/ Insert
/ Remove
Operationen.
Dies bedeutet, dass Sie den Typ ändern müssen, wenn Sie das Verhalten der Auflistung in Zukunft ändern müssen (z. B. um Nullobjekte abzulehnen, die von Personen hinzugefügt werden sollen, oder um zusätzliche Arbeiten auszuführen, wenn dies geschieht, z. B. das Aktualisieren Ihres Klassenstatus) Von der Sammlung kehren Sie zu einer Unterklasse zurück, die eine brechende Schnittstellenänderung darstellt (natürlich kann das Ändern der Semantik von Dingen wie dem Nichtzulassen von Null auch eine Schnittstellenänderung sein, aber Dinge wie das Aktualisieren Ihres internen Klassenstatus wären dies nicht).
Wenn Sie also entweder eine Klasse zurückgeben, die leicht in Unterklassen wie Collection<T>
oder eine Schnittstelle wie unterteilt werden kann IList<T>
, ICollection<T>
oder IEnumerable<T>
Ihre interne Implementierung so ändern können, dass sie Ihren Anforderungen entspricht, ohne den Code der Verbraucher zu beschädigen, da sie weiterhin als zurückgegeben werden kann der Typ, den sie erwarten.
API-Einfachheit
List<T>
enthält viele nützliche Funktionen wie BinarySearch
, Sort
und so weiter. Wenn es sich jedoch um eine Sammlung handelt, die Sie verfügbar machen, steuern Sie wahrscheinlich die Semantik der Liste und nicht die Verbraucher. Während Ihre Klasse diese Operationen möglicherweise intern benötigt, ist es sehr unwahrscheinlich, dass Verbraucher Ihrer Klasse sie anrufen möchten (oder sollten).
Indem Sie eine einfachere Sammlungsklasse oder -schnittstelle anbieten, reduzieren Sie die Anzahl der Mitglieder, die Benutzer Ihrer API sehen, und erleichtern ihnen die Verwendung.
Ich würde persönlich erklären, dass es sich eher um eine Schnittstelle als um eine konkrete Sammlung handelt. Wenn Sie wirklich Listenzugriff wünschen, verwenden Sie
IList<T>
. Andernfalls berücksichtigen SieICollection<T>
undIEnumerable<T>
.quelle
We recommend using Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<TKey,TItem> for outputs and properties and interfaces IEnumerable<T>, ICollection<T>, IList<T> for inputs.
CA1002 scheint mit Krzysztofs Kommentaren übereinzustimmen. Ich kann mir nicht vorstellen, warum eine konkrete Sammlung anstelle einer Schnittstelle empfohlen wird und warum die Unterscheidung zwischen Ein- / Ausgängen.ReadOnlyCollection<T>
würde eine Eingabe im Allgemeinen keinen Sinn ergeben. Ebenso,IList<T>
wie eine Eingabe sagt, "Ich brauche Sort () oder ein anderes Mitglied, das eine IList hat", was für eine Ausgabe keinen Sinn ergibt. Aber ich meinte, warumICollection<T>
sollte als Eingabe undCollection<T>
als Ausgabe empfohlen werden. Warum nicht auchICollection<T>
als Ausgabe verwenden, wie Sie vorgeschlagen haben?Collection<T>
undReadOnlyCollection<T>
beide stammen vonICollection<T>
(dh es gibt keineIReadOnlyCollection<T>
). Wenn Sie die Schnittstelle zurückgeben, ist nicht klar, um welche es sich handelt und ob sie geändert werden kann. Trotzdem danke für deine Eingabe. Dies war eine gute Überprüfung der geistigen Gesundheit für mich.Ich glaube, noch hat niemand den "Warum" -Teil beantwortet ... also los geht's. Der Grund, warum "Sie" a
Collection<T>
anstelle von a verwenden sollten,List<T>
liegt darin, dassList<T>
jeder, der Zugriff auf Ihr Objekt erhält, die Elemente in der Liste ändern kann, wenn Sie a verfügbar machen . WährendCollection<T>
soll anzeigen, dass Sie Ihre eigenen Methoden "Hinzufügen", "Entfernen" usw. erstellen.Sie müssen sich wahrscheinlich keine Sorgen machen, da Sie die Benutzeroberfläche wahrscheinlich nur für sich selbst (oder vielleicht für einige Kollegen) codieren. Hier ist ein weiteres Beispiel, das Sinn machen könnte.
Wenn Sie ein öffentliches Array haben, z.
Sie würden denken, dass, weil es nur einen "get" -Zugriff gibt, niemand mit den Werten herumspielen kann, aber das ist nicht wahr. Jeder kann die Werte dort einfach so ändern:
Persönlich würde ich
List<T>
in den meisten Fällen nur verwenden . Wenn Sie jedoch eine Klassenbibliothek entwerfen, die Sie an zufällige Entwickler weitergeben möchten, und sich auf den Status der Objekte verlassen müssen, sollten Sie Ihre eigene Sammlung erstellen und von dort aus sperren: )quelle
Es geht hauptsächlich darum, Ihre eigenen Implementierungen zu abstrahieren, anstatt das List-Objekt, das direkt bearbeitet werden soll, verfügbar zu machen.
Es ist keine gute Praxis, andere Objekte (oder Personen) den Status Ihrer Objekte direkt ändern zu lassen. Denken Sie an Getter / Setter.
Sammlung -> Für normale Sammlung
ReadOnlyCollection -> Für Sammlungen, die nicht geändert werden sollten
KeyedCollection -> Wenn Sie stattdessen Wörterbücher möchten.
Wie Sie das Problem beheben können, hängt davon ab, was Ihre Klasse tun soll und welchen Zweck die GetList () -Methode hat. Können Sie das näher erläutern?
quelle
ReadOnlyCollection
den anderen beiden gehorcht es nicht.GetList()
, ihm besser helfen zu können.Collection<T>
hilft bei der Abstraktion der internen Implementierung und verhindert die direkte Manipulation der internen Liste. Wie?Collection<T>
ist lediglich ein Wrapper, der mit derselben übergebenen Instanz arbeitet. Es ist eine dynamische Sammlung, die für die Vererbung gedacht ist, sonst nichts (Gregs Antwort ist hier relevanter).In solchen Fällen versuche ich normalerweise, die geringste erforderliche Implementierungsmenge bereitzustellen. Wenn die Verbraucher nicht wissen müssen, dass Sie tatsächlich eine Liste verwenden, müssen Sie keine Liste zurückgeben. Wenn Sie zurückkehren, wie Microsoft eine Sammlung vorschlägt, verbergen Sie die Tatsache, dass Sie eine Liste verwenden, vor den Verbrauchern Ihrer Klasse und isolieren sie gegen eine interne Änderung.
quelle
Etwas hinzuzufügen, obwohl es lange her ist, dass dies gefragt wurde.
Wenn Ihr
List<T>
Listentyp von abgeleitet istCollection<T>
, können Sie die geschützten virtuellen Methoden, dieCollection<T>
implementiert werden, nicht implementieren. Dies bedeutet, dass der von Ihnen abgeleitete Typ nicht reagieren kann, wenn Änderungen an der Liste vorgenommen werden. Dies liegt daran,List<T>
dass Sie wissen, wann Sie Elemente hinzufügen oder entfernen. In der Lage zu sein, auf Benachrichtigungen zu antworten, ist ein Aufwand undList<T>
bietet ihn daher nicht an.In Fällen, in denen externer Code Zugriff auf Ihre Sammlung hat, haben Sie möglicherweise keine Kontrolle darüber, wann ein Element hinzugefügt oder entfernt wird. Auf diese
Collection<T>
Weise können Sie feststellen, wann Ihre Liste geändert wurde.quelle
Ich sehe kein Problem damit, so etwas zurückzugeben
Wenn ich eine nicht verbundene Kopie der internen Daten oder ein getrenntes Ergebnis einer Datenabfrage zurückgegeben habe, kann ich sicher zurückkehren,
List<TItem>
ohne Implementierungsdetails preiszugeben, und die zurückgegebenen Daten auf bequeme Weise verwenden.Dies hängt jedoch davon ab, welche Art von Verbraucher ich erwarte - wenn es sich um ein Datenraster handelt, das ich lieber zurückgeben möchte
IEnumerable<TItem>
, wird dies in den meisten Fällen ohnehin die kopierte Liste der Artikel sein :)quelle
Nun, die Collection-Klasse ist wirklich nur eine Wrapper-Klasse für andere Sammlungen, um deren Implementierungsdetails und andere Funktionen zu verbergen. Ich denke, dies hat etwas mit der Eigenschaft zu tun, die das Codierungsmuster in objektorientierten Sprachen verbirgt.
Ich denke, Sie sollten sich darüber keine Sorgen machen, aber wenn Sie dem Code-Analyse-Tool wirklich gefallen möchten, gehen Sie einfach wie folgt vor:
quelle
Collection<T>
schützt meines Wissens weder sich selbst noch die zugrunde liegende Sammlung.Collection<T>
Ihre zugrunde liegende Sammlung sofort schützt.