Ich weiß, dass IList die Schnittstelle und List der konkrete Typ ist, aber ich weiß immer noch nicht, wann ich jeden verwenden soll. Was ich jetzt mache, ist, wenn ich die Sortier- oder FindAll-Methoden nicht benötige, verwende ich die Schnittstelle. Habe ich recht? Gibt es eine bessere Möglichkeit zu entscheiden, wann die Schnittstelle oder der konkrete Typ verwendet werden soll?
178
Antworten:
Ich befolge zwei Regeln:
Wenn Sie also eine Funktion oder Methode schreiben, die eine Sammlung benötigt, schreiben Sie sie nicht in eine Liste, sondern in eine IList <T>, eine ICollection <T> oder eine IEnumerable <T>. Die generischen Schnittstellen funktionieren auch für heterogene Listen, da System.Object auch ein T sein kann. Dies erspart Ihnen Kopfschmerzen, wenn Sie sich später für die Verwendung eines Stacks oder einer anderen Datenstruktur entscheiden. Wenn alles, was Sie in der Funktion tun müssen, darin besteht, sie durchzuarbeiten, ist IEnumerable <T> wirklich alles, wonach Sie fragen sollten.
Wenn Sie andererseits ein Objekt aus einer Funktion zurückgeben, möchten Sie dem Benutzer die größtmögliche Anzahl von Operationen bieten, ohne dass er herumwirbeln muss. Wenn es sich in diesem Fall intern um eine Liste <T> handelt, geben Sie eine Kopie als Liste <T> zurück.
quelle
if...else
Kette mit demis
Schlüsselwort verwenden kann, um die Zahl zu bestimmen einen viel reicheren Typ dafür herausholen und am Ende darauf werfen und ihn trotzdem benutzen. Es ist also nicht unbedingt garantiert, dass Sie etwas über eine grundlegende Benutzeroberfläche verbergen, anstatt es nur zu verdecken. Wenn Sie es jedoch schwieriger machen, kann der Verfasser des konsumierenden Codes auch zweimal darüber nachdenken, wie er verwendet wird.Add()
undRemove()
Auswirkungen haben können. Die Rückgabe einer schreibgeschützten Schnittstelle, wie sieIEnumerable
häufig für Datenabrufmethoden verwendet wird. Ihr Verbraucher kann es nach Bedarf in einen reichhaltigeren Typ projizieren.Von FxCop überprüfte Microsoft-Richtlinien raten von der Verwendung von List <T> in öffentlichen APIs ab - bevorzugen Sie IList <T>.
Übrigens deklariere ich jetzt fast immer eindimensionale Arrays als IList <T>, was bedeutet, dass ich die IList <T> .Count-Eigenschaft anstelle von Array.Length konsistent verwenden kann. Beispielsweise:
quelle
Es gibt eine wichtige Sache, die die Leute immer zu übersehen scheinen:
Sie können ein einfaches Array an etwas übergeben, das einen
IList<T>
Parameter akzeptiert , und dann können SieIList.Add()
eine Laufzeitausnahme aufrufen und erhalten:Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.
Betrachten Sie beispielsweise den folgenden Code:
Wenn Sie dies wie folgt aufrufen, erhalten Sie eine Laufzeitausnahme:
Dies liegt daran, dass die Verwendung einfacher Arrays mit
IList<T>
gegen das Liskov-Substitutionsprinzip verstößt.Wenn Sie anrufen, sollten
IList<T>.Add()
Sie aus diesem Grund in Betracht ziehen, einList<T>
anstelle eines zu verlangenIList<T>
.quelle
List<T>
überIList<T>
, sollten Sie auch die Gründe wissen, warumIList<T>
empfohlen. (Zum Beispiel blogs.msdn.microsoft.com/kcwalina/2005/09/26/… )IList<T>.Add()
. Ich sage nicht, dass Sie nicht verwenden solltenIList<T>
- ich weise nur auf eine mögliche Falle hin. (Ich neige dazu,IEnumerable<T>
oderIReadOnlyList<T>
oderIReadOnlyCollection<T>
lieber zu verwenden,IList<T>
wenn ich kann.)Ich würde Lees Rat zustimmen, Parameter zu übernehmen, aber nicht zurückzukehren.
Wenn Sie Ihre Methoden angeben, um eine Schnittstelle zurückzugeben, können Sie die genaue Implementierung später ändern, ohne dass die konsumierende Methode dies jemals weiß. Ich dachte, ich müsste nie von einer Liste <T> wechseln, sondern später, um eine benutzerdefinierte Listenbibliothek für die zusätzliche Funktionalität zu verwenden. Da ich nur eine IList <T> zurückgegeben hatte, musste keiner der Benutzer der Bibliothek seinen Code ändern.
Dies muss natürlich nur für Methoden gelten, die von außen sichtbar sind (dh öffentliche Methoden). Ich persönlich verwende Schnittstellen auch im internen Code, aber da Sie den gesamten Code selbst ändern können, wenn Sie wichtige Änderungen vornehmen, ist dies nicht unbedingt erforderlich.
quelle
IEnumerable
Sie sollten versuchen, den am wenigsten spezifischen Typ zu verwenden, der Ihrem Zweck entspricht.
IEnumerable
ist weniger spezifisch alsIList
.Sie verwenden diese Option,
IEnumerable
wenn Sie die Elemente in einer Sammlung durchlaufen möchten.IList
IList
implementiertIEnumerable
.Sie sollten verwenden,
IList
wenn Sie Zugriff per Index auf Ihre Sammlung benötigen, Elemente hinzufügen und löschen usw.Liste
List
implementiertIList
.quelle
Es ist immer am besten, den niedrigstmöglichen Basistyp zu verwenden. Dies gibt dem Implementierer Ihrer Schnittstelle oder dem Konsumenten Ihrer Methode die Möglichkeit, hinter den Kulissen zu verwenden, was er möchte.
Für Sammlungen sollten Sie nach Möglichkeit IEnumerable verwenden. Dies bietet die größte Flexibilität, ist jedoch nicht immer geeignet.
quelle
ToList()
IhreIEnumerable<T>
Rücksendung zu senden , die bereits eine Liste war, und geben SieIList<T>
stattdessen eine zurück. Jetzt können Kunden mühelos von dem profitieren, was Sie bieten können.Wenn Sie innerhalb einer einzelnen Methode arbeiten (oder in einigen Fällen sogar in einer einzelnen Klasse oder Assembly) und niemand außerhalb sehen wird, was Sie tun, verwenden Sie die Fülle einer Liste. Wenn Sie jedoch mit externem Code interagieren, z. B. wenn Sie eine Liste von einer Methode zurückgeben, möchten Sie die Schnittstelle nur deklarieren, ohne sich unbedingt an eine bestimmte Implementierung zu binden, insbesondere wenn Sie keine Kontrolle darüber haben, wer gegen Ihre kompiliert Code danach. Wenn Sie mit einem konkreten Typ begonnen haben und sich entschieden haben, zu einem anderen zu wechseln, auch wenn er dieselbe Schnittstelle verwendet, werden Sie den Code eines anderen Benutzers beschädigen, es sei denn, Sie haben mit einer Schnittstelle oder einem abstrakten Basistyp begonnen.
quelle
Ich glaube nicht, dass es feste Regeln für diese Art von Dingen gibt, aber ich halte mich normalerweise an die Richtlinie, den leichtesten Weg zu gehen, bis es absolut notwendig ist.
Angenommen, Sie haben eine
Person
Klasse und eineGroup
Klasse. EineGroup
Instanz hat viele Leute, daher wäre eine Liste hier sinnvoll. Wenn ich das Listenobjekt in deklariere, verwendeGroup
ich einIList<Person>
und instanziiere es alsList
.Und wenn Sie nicht einmal alles brauchen
IList
, können Sie es auch immer verwendenIEnumerable
. Bei modernen Compilern und Prozessoren gibt es meines Erachtens keinen Geschwindigkeitsunterschied, daher ist dies eher eine Frage des Stils.quelle
Meistens ist es besser, den allgemeinsten verwendbaren Typ zu verwenden, in diesem Fall die IList oder noch besser die IEnumerable-Schnittstelle, damit Sie die Implementierung zu einem späteren Zeitpunkt bequem wechseln können.
In .NET 2.0 gibt es jedoch eine ärgerliche Sache: IList verfügt nicht über eine Sort () -Methode. Sie können stattdessen einen mitgelieferten Adapter verwenden:
quelle
Sie sollten die Schnittstelle nur verwenden, wenn Sie sie benötigen, z. B. wenn Ihre Liste in eine andere IList-Implementierung als List umgewandelt wurde. Dies gilt beispielsweise, wenn Sie NHibernate verwenden, mit dem ILists beim Abrufen von Daten in ein NHibernate-Bag-Objekt umgewandelt werden.
Wenn List die einzige Implementierung ist, die Sie jemals für eine bestimmte Sammlung verwenden werden, können Sie sie als konkrete List-Implementierung deklarieren.
quelle
In Situationen, auf die ich normalerweise stoße, verwende ich IList selten direkt.
Normalerweise benutze ich es nur als Argument für eine Methode
Auf diese Weise kann ich eine generische Verarbeitung für fast jedes Array im .NET-Framework durchführen, es sei denn, es wird IEnumerable und nicht IList verwendet, was manchmal vorkommt.
Es kommt wirklich auf die Art von Funktionalität an, die Sie benötigen. Ich würde in den meisten Fällen die Verwendung der List-Klasse vorschlagen. IList eignet sich am besten, wenn Sie ein benutzerdefiniertes Array erstellen müssen, das einige sehr spezifische Regeln enthalten kann, die Sie in eine Sammlung einkapseln möchten, damit Sie sich nicht wiederholen, aber dennoch möchten, dass .NET es als Liste erkennt.
quelle
Mit dem AList-Objekt können Sie eine Liste erstellen, Dinge hinzufügen, entfernen, aktualisieren, indizieren usw. Die Liste wird immer dann verwendet, wenn Sie nur eine generische Liste möchten, in der Sie den Objekttyp angeben.
IList hingegen ist eine Schnittstelle. Wenn Sie einen eigenen Listentyp erstellen möchten, z. B. eine Listenklasse namens BookList, können Sie über die Schnittstelle grundlegende Methoden und Strukturen für Ihre neue Klasse festlegen. IList ist für den Fall gedacht, dass Sie eine eigene, spezielle Unterklasse erstellen möchten, die List implementiert.
Ein weiterer Unterschied ist: IList ist eine Schnittstelle und kann nicht instanziiert werden. List ist eine Klasse und kann instanziiert werden. Es bedeutet:
quelle