Liste <T> oder IList <T> [geschlossen]

495

Kann mir jemand erklären, warum ich IList over List in C # verwenden möchte?

Verwandte Frage: Warum wird es als schlecht angesehen, zu belichtenList<T>

Erdnuss
quelle
1
Internet-Suche nach "Code zu einer Schnittstelle keine Implementierung" und Sie können den ganzen Tag lesen .. und finden ein paar h0ly Kriege.
GranadaCoder

Antworten:

446

Wenn Sie Ihre Klasse über eine Bibliothek verfügbar machen, die andere verwenden, möchten Sie sie im Allgemeinen über Schnittstellen und nicht über konkrete Implementierungen verfügbar machen. Dies ist hilfreich, wenn Sie die Implementierung Ihrer Klasse später ändern, um eine andere konkrete Klasse zu verwenden. In diesem Fall müssen die Benutzer Ihrer Bibliothek ihren Code nicht aktualisieren, da sich die Benutzeroberfläche nicht ändert.

Wenn Sie es nur intern verwenden, ist es Ihnen möglicherweise nicht so wichtig, und die Verwendung ist List<T>möglicherweise in Ordnung.

Tvanfosson
quelle
19
Ich verstehe den (subtilen) Unterschied nicht. Gibt es ein Beispiel, auf das Sie mich hinweisen könnten?
StingyJack
134
Angenommen, Sie haben ursprünglich List <T> verwendet und wollten eine spezielle CaseInsensitiveList <T> verwenden, die beide IList <T> implementieren. Wenn Sie den konkreten Typ verwenden, müssen alle Anrufer aktualisiert werden. Wenn der Anrufer als IList <T> angezeigt wird, muss er nicht geändert werden.
Tvanfosson
46
Ah. OK. Ich verstehe das. Auswahl des kleinsten gemeinsamen Nenners für einen Vertrag. Vielen Dank!
StingyJack
16
Dieses Prinzip ist ein Beispiel für die Kapselung, eine der drei Säulen der objektorientierten Programmierung. Die Idee ist, dass Sie die Implementierungsdetails vor dem Benutzer verbergen und stattdessen eine stabile Schnittstelle bereitstellen. Dies dient dazu, die Abhängigkeit von Details zu verringern, die sich in Zukunft ändern könnten.
Jason
14
Beachten Sie auch, dass T []: IList <T>, sodass Sie aus Leistungsgründen jederzeit von der Rückgabe einer Liste <T> von Ihrer Prozedur zur Rückgabe eines T [] wechseln können und wenn die Prozedur für die Rückgabe von IList <T> deklariert ist (oder vielleicht ICollection <T> oder IEnumerable <T>) nichts anderes müsste geändert werden.
Yfeldblum
322

Die weniger beliebte Antwort ist, dass Programmierer gerne so tun, als würden ihre Software auf der ganzen Welt wiederverwendet, wenn tatsächlich die meisten Projekte von einer kleinen Anzahl von Leuten verwaltet werden und Sie sich täuschen, wie nett die Soundbites im Zusammenhang mit der Benutzeroberfläche auch sein mögen du selber.

Architektur Astronauten . Die Chancen, dass Sie jemals eine eigene IList schreiben, die etwas zu den bereits im .NET Framework vorhandenen hinzufügt, sind so gering, dass es sich um theoretische Jelly Tots handelt, die "Best Practices" vorbehalten sind.

Software-Astronauten

Wenn Sie gefragt werden, was Sie in einem Interview verwenden, sagen Sie natürlich IList, lächeln und beide freuen sich, dass Sie so schlau sind. Oder für eine öffentlich zugängliche API, IList. Hoffentlich verstehst du meinen Standpunkt.

Arec Barrwin
quelle
65
Ich muss Ihrer sardonischen Antwort nicht zustimmen. Ich bin nicht ganz anderer Meinung als das Gefühl, dass Überarchitektur ein echtes Problem ist. Allerdings denke ich, dass gerade bei Sammlungen diese Schnittstellen wirklich glänzen. Angenommen, ich habe eine Funktion, die zurückgibt IEnumerable<string>. Innerhalb der Funktion kann ich eine List<string>für einen internen Sicherungsspeicher verwenden, um meine Sammlung zu generieren, aber ich möchte nur, dass Aufrufer deren Inhalt auflisten, nicht hinzufügen oder entfernen. Wenn Sie eine Schnittstelle als Parameter akzeptieren, wird eine ähnliche Meldung angezeigt: "Ich benötige eine Sammlung von Zeichenfolgen, aber keine Sorge, ich werde sie nicht ändern."
Joshperry
38
Bei der Softwareentwicklung dreht sich alles um die Übersetzung von Absichten. Wenn Sie der Meinung sind, dass Schnittstellen nur zum Erstellen übergroßer, grandioser Architekturen nützlich sind und keinen Platz in kleinen Läden haben, dann hoffe ich, dass die Person, die Ihnen im Interview gegenüber sitzt, nicht ich bin.
Joshperry
48
Jemand musste diesen Arec sagen ... selbst wenn Sie alle möglichen akademischen Muster haben, die Hasspost verfolgen. +1 für alle von uns, die es hassen, wenn eine kleine App mit Schnittstellen geladen ist und wenn wir auf "Definition finden" klicken, gelangen wir an einen anderen Ort als die Ursache des Problems ... Kann ich mir den Ausdruck "Architekturastronauten" ausleihen? Ich kann sehen, dass es nützlich sein wird.
Gats
6
Wenn es möglich wäre, gebe ich Ihnen 1000 Punkte für diese Antwort. : D
Samuel
8
Ich habe über das umfassendere Ergebnis der Musterjagd gesprochen. Schnittstellen für gemeinsame Schnittstellen gut, zusätzliche Ebenen, um ein Muster zu verfolgen, schlecht.
Gats
186

Schnittstelle ist ein Versprechen (oder ein Vertrag).

Wie immer bei den Versprechungen - kleiner desto besser .

Rinat Abdullin
quelle
56
Nicht immer besser, nur einfacher zu halten! :)
Kirk Broadhurst
5
Ich verstehe das nicht. So IListist das Versprechen. Welches ist das kleinere und bessere Versprechen hier? Das ist nicht logisch.
Nawfal
3
Für jede andere Klasse würde ich zustimmen. Aber nicht für List<T>, weil AddRangeauf der Schnittstelle nicht definiert ist.
Jesse de Wit
3
Dies ist in diesem speziellen Fall nicht wirklich hilfreich. Das beste Versprechen ist das, das gehalten wird. IList<T>macht Versprechungen, die es nicht halten kann. Zum Beispiel gibt es eine AddMethode, die ausgelöst werden kann, wenn IList<T>sie schreibgeschützt ist. List<T>andererseits ist immer beschreibbar und hält somit immer seine Versprechen. Auch seit .NET 4.6 haben wir jetzt IReadOnlyCollection<T>und IReadOnlyList<T>die passen fast immer besser als IList<T>. Und sie sind kovariant. Vermeiden Sie IList<T>!
ZunTzu
@ZunTzu Ich würde argumentieren, dass jemand, der eine unveränderliche Sammlung als veränderlich ausgibt, den vorgelegten Vertrag wissentlich gebrochen hat - es ist kein Problem mit dem Vertrag selbst, z IList<T>. Jemand könnte genauso gut implementieren IReadOnlyList<T>und jede Methode auch eine Ausnahme auslösen lassen. Es ist das Gegenteil von Ententypisierung - Sie nennen es eine Ente, aber es kann nicht wie eine quaken. Dies ist jedoch Teil des Vertrags, auch wenn der Compiler ihn nicht durchsetzen kann. Ich stimme jedoch zu 100% zu, dass IReadOnlyList<T>oder IReadOnlyCollection<T>sollte nur für den Lesezugriff verwendet werden.
Shelby Oldfield
93

Einige Leute sagen "immer verwenden IList<T>statt List<T>".
Sie möchten, dass Sie Ihre Methodensignaturen von void Foo(List<T> input)bis ändern void Foo(IList<T> input).

Diese Leute sind falsch.

Es ist nuancierter als das. Wenn Sie eine IList<T>als Teil der öffentlichen Schnittstelle an Ihre Bibliothek zurückgeben, lassen Sie sich interessante Optionen, um möglicherweise in Zukunft eine benutzerdefinierte Liste zu erstellen. Möglicherweise benötigen Sie diese Option nie, aber es ist ein Argument. Ich denke, es ist das gesamte Argument für die Rückgabe der Schnittstelle anstelle des konkreten Typs. Es ist erwähnenswert, aber in diesem Fall hat es einen schwerwiegenden Fehler.

Als kleines Gegenargument stellen Sie möglicherweise fest, dass jeder einzelne Anrufer List<T>ohnehin einen benötigt , und der Anrufcode ist übersät.ToList()

Aber viel wichtiger ist, wenn Sie eine IList als Parameter akzeptieren, sollten Sie besser vorsichtig sein, weil IList<T>und List<T>sich nicht gleich verhalten. Trotz der Ähnlichkeit im Namen und trotz der gemeinsamen Nutzung einer Schnittstelle legen sie nicht denselben Vertrag offen .

Angenommen, Sie haben diese Methode:

public Foo(List<int> a)
{
    a.Add(someNumber);
}

Ein hilfreicher Kollege "refaktoriert" die zu akzeptierende Methode IList<int>.

Ihr Code ist jetzt defekt, weil int[]implementiert IList<int>, hat aber eine feste Größe. Der Vertrag für ICollection<T>(die Basis von IList<T>) erfordert den Code, mit dem das IsReadOnlyFlag überprüft wird, bevor versucht wird, Elemente zur Sammlung hinzuzufügen oder daraus zu entfernen. Der Vertrag für List<T>nicht.

Das Liskov-Substitutionsprinzip (vereinfacht) besagt, dass ein abgeleiteter Typ anstelle eines Basistyps ohne zusätzliche Vor- oder Nachbedingungen verwendet werden kann.

Dies scheint das Liskov-Substitutionsprinzip zu brechen.

 int[] array = new[] {1, 2, 3};
 IList<int> ilist = array;

 ilist.Add(4); // throws System.NotSupportedException
 ilist.Insert(0, 0); // throws System.NotSupportedException
 ilist.Remove(3); // throws System.NotSupportedException
 ilist.RemoveAt(0); // throws System.NotSupportedException

Aber das tut es nicht. Die Antwort darauf ist, dass im Beispiel IList <T> / ICollection <T> falsch verwendet wurde. Wenn Sie eine ICollection <T> verwenden, müssen Sie das IsReadOnly-Flag überprüfen.

if (!ilist.IsReadOnly)
{
   ilist.Add(4);
   ilist.Insert(0, 0); 
   ilist.Remove(3);
   ilist.RemoveAt(0);
}
else
{
   // what were you planning to do if you were given a read only list anyway?
}

Wenn Ihnen jemand ein Array oder eine Liste übergibt, funktioniert Ihr Code einwandfrei, wenn Sie jedes Mal das Flag überprüfen und einen Fallback haben ... Aber wirklich; Wer macht das? Wissen Sie nicht im Voraus, ob Ihre Methode eine Liste benötigt, die zusätzliche Mitglieder aufnehmen kann? Geben Sie das nicht in der Methodensignatur an? Was genau wollten Sie tun, wenn Sie eine schreibgeschützte Liste erhalten haben int[]?

Sie können einen List<T>In-Code ersetzen , der IList<T>/ ICollection<T> korrekt verwendet . Sie können nicht garantieren, dass Sie einen IList<T>/ ICollection<T>in-Code ersetzen können , der verwendet wird List<T>.

In vielen Argumenten zur Verwendung von Abstraktionen anstelle konkreter Typen wird auf das Prinzip der Einzelverantwortung / Schnittstellentrennung verwiesen - abhängig von der engstmöglichen Schnittstelle. In den meisten Fällen, wenn Sie a verwenden List<T>und glauben, Sie könnten stattdessen eine schmalere Oberfläche verwenden - warum nicht IEnumerable<T>? Dies passt oft besser, wenn Sie keine Elemente hinzufügen müssen. Wenn Sie der Sammlung hinzufügen müssen, verwenden Sie den konkreten Typ List<T>.

Für mich IList<T>(und ICollection<T>) ist der schlechteste Teil des .NET Frameworks. IsReadOnlyverstößt gegen das Prinzip der geringsten Überraschung. Eine Klasse, die beispielsweise Arraydas Hinzufügen, Einfügen oder Entfernen von Elementen niemals zulässt, sollte keine Schnittstelle mit den Methoden Hinzufügen, Einfügen und Entfernen implementieren. (Siehe auch /software/306105/implementing-an-interface-when-you-dont-need-one-of-the-properties )

Passt es IList<T>gut zu Ihrer Organisation? Wenn ein Kollege Sie stellt eine Methode zum Ändern der Signatur zu verwenden IList<T>statt List<T>, fragen sie , wie sie ein Element eine hinzufügen würden IList<T>. Wenn sie nichts wissen IsReadOnly(und die meisten Leute nicht wissen ), dann verwenden Sie es nicht IList<T>. Je.


Beachten Sie, dass das IsReadOnly-Flag von ICollection <T> stammt und angibt, ob Elemente zur Sammlung hinzugefügt oder daraus entfernt werden können. Aber nur um die Dinge wirklich zu verwirren, gibt es keinen Hinweis darauf, ob sie ersetzt werden können, was im Fall von Arrays (die IsReadOnlys == true zurückgeben) sein kann.

Weitere Informationen zu IsReadOnly finden Sie unter msdn-Definition von ICollection <T> .IsReadOnly

Perfektionist
quelle
5
Tolle, tolle Antwort. Ich möchte hinzufügen, dass Sie die aktuellen Mitglieder auch dann ändern können , wenn IsReadOnlyes sich trueum eine IListhandelt! Vielleicht sollte diese Eigenschaft benannt werden IsFixedSize?
Xofz
(das wurde mit dem Bestehen eines Arrayals getestet IList, deshalb konnte ich die aktuellen Mitglieder ändern)
xofz
1
@SamPearson In .NET 1 gab es eine IsFixedSize-Eigenschaft für IList, die nicht in der generischen IList <T> von .NET 2.0 enthalten war, wo sie mit IsReadOnly konsolidiert wurde, was zu überraschendem Verhalten bei Arrays führte. Es gibt einen detaillierten Blog über die subtilen Unterschiede hier: Enterprisecraftsmanship.com/2014/11/22/…
Perfektionist
7
Hervorragende Antwort! Außerdem haben wir seit .NET 4.6 jetzt IReadOnlyCollection<T>und IReadOnlyList<T>die passen fast immer besser als IList<T>, haben aber nicht die gefährliche faule Semantik von IEnumerable<T>. Und sie sind kovariant. Vermeiden Sie IList<T>!
ZunTzu
37

List<T>ist eine spezifische Implementierung von IList<T>, bei der es sich um einen Container handelt, der auf die gleiche Weise wie ein lineares Array adressiert werden kannT[] Verwendung eines ganzzahligen Index . Wenn Sie IList<T>als Typ des Argumentes der Methode angeben, geben Sie nur an, dass Sie bestimmte Funktionen des Containers benötigen.

Beispielsweise erzwingt die Schnittstellenspezifikation keine bestimmte zu verwendende Datenstruktur. Die Implementierung von List<T>erfolgt mit derselben Leistung für den Zugriff auf, das Löschen und Hinzufügen von Elementen als lineares Array. Sie können sich jedoch eine Implementierung vorstellen, die stattdessen durch eine verknüpfte Liste unterstützt wird, für die das Hinzufügen von Elementen am Ende billiger ist (konstante Zeit), der Direktzugriff jedoch viel teurer ist. (Beachten Sie, dass .NET LinkedList<T>dies nicht tut implementiert IList<T>.)

In diesem Beispiel erfahren Sie auch, dass es Situationen geben kann, in denen Sie die Implementierung und nicht die Schnittstelle in der Argumentliste angeben müssen: In diesem Beispiel, wenn Sie ein bestimmtes Zugriffsleistungsmerkmal benötigen. Dies ist normalerweise für eine bestimmte Implementierung eines Containers garantiert (List<T> Dokumentation: "Es implementiert die IList<T>generische Schnittstelle mithilfe eines Arrays, dessen Größe nach Bedarf dynamisch erhöht wird.").

Darüber hinaus möchten Sie möglicherweise die geringste Funktionalität bereitstellen, die Sie benötigen. Zum Beispiel. Wenn Sie den Inhalt der Liste nicht ändern müssen, sollten Sie wahrscheinlich die Verwendung in Betracht ziehen IEnumerable<T>, die IList<T>erweitert wird.

ILoveFortran
quelle
In Bezug auf Ihre letzte Aussage zur Verwendung von IEnumerable anstelle von IList. Dies wird nicht immer empfohlen. Nehmen Sie zum Beispiel WPF, das nur ein Wrapper-IList-Objekt erstellt und so Auswirkungen auf perf - msdn.microsoft.com/en-us/library/bb613546.aspx
HAdes
1
Gute Antwort, Leistungsgarantien sind etwas, das eine Schnittstelle nicht liefern kann. In einigen Codes kann dies sehr wichtig sein und die Verwendung konkreter Klassen kommuniziert Ihre Absicht, Ihre Notwendigkeit für diese bestimmte Klasse. Eine Schnittstelle sagt andererseits: "Ich muss nur diese Methoden aufrufen, kein anderer Vertrag impliziert."
Joshperry
1
@joshperry Wenn Sie die Leistung einer Schnittstelle stört, befinden Sie sich in erster Linie auf der falschen Plattform. Impo, das ist Mikrooptimierung.
Nawfal
@nawfal Ich habe die Leistungsvorteile von Schnittstellen nicht kommentiert. Ich stimmte zu und kommentierte die Tatsache, dass Sie, wenn Sie eine konkrete Klasse als Argument herausstellen, eine Leistungsabsicht kommunizieren können. Nehmen LinkedList<T>gegen Nehmen List<T>gegen IList<T>alle kommunizieren etwas von den Leistungsgarantien, die für den aufgerufenen Code erforderlich sind.
Joshperry
28

Ich würde die Frage ein wenig umdrehen, anstatt zu rechtfertigen, warum Sie die Schnittstelle über der konkreten Implementierung verwenden sollten, versuchen Sie zu rechtfertigen, warum Sie die konkrete Implementierung anstelle der Schnittstelle verwenden würden. Wenn Sie es nicht rechtfertigen können, verwenden Sie die Schnittstelle.

Patrik Hägne
quelle
1
Sehr interessante Art darüber nachzudenken. Und eine gute Denkweise beim Programmieren - danke.
Erdnuss
Gut gesagt! Da die Schnittstelle flexibler ist, sollten Sie wirklich begründen müssen, was die konkrete Implementierung für Sie bedeutet.
Cory House
9
Tolle Denkweise. Trotzdem kann ich es beantworten: Mein Grund heißt AddRange ()
PPC
4
Mein Grund heißt Add (). Manchmal möchten Sie eine Liste, von der Sie wissen , dass sie zusätzliche Elemente enthalten kann, sicher? Siehe meine Antwort.
Perfektionist
19

IList <T> ist eine Schnittstelle, mit der Sie eine andere Klasse erben und dennoch IList <T> implementieren können, während das Erben von List <T> dies verhindert.

Wenn es beispielsweise eine Klasse A gibt und Ihre Klasse B diese erbt, können Sie List <T> nicht verwenden

class A : B, IList<T> { ... }
Diadistis
quelle
15

Ein Prinzip von TDD und OOP ist im Allgemeinen das Programmieren auf eine Schnittstelle, keine Implementierung.

In diesem speziellen Fall spielt es keine Rolle, da es sich im Wesentlichen um ein Sprachkonstrukt handelt, nicht um ein benutzerdefiniertes, aber sagen Sie beispielsweise, dass Sie festgestellt haben, dass List etwas nicht unterstützt, das Sie benötigen. Wenn Sie IList im Rest der App verwendet haben, können Sie List um Ihre eigene benutzerdefinierte Klasse erweitern und diese dennoch ohne Refactoring weitergeben.

Die Kosten dafür sind minimal. Warum sparen Sie sich nicht später die Kopfschmerzen? Darum geht es beim Interface-Prinzip.

Annakata
quelle
3
Wenn Ihre ExtendedList <T> List <T> erbt, können Sie sie dennoch in einen List <T> -Vertrag einfügen. Dieses Argument funktioniert nur, wenn Sie Ihre eigene Implementierung von IList <T> von sratch schreiben (oder zumindest ohne List <T> zu erben)
PPC
14
public void Foo(IList<Bar> list)
{
     // Do Something with the list here.
}

In diesem Fall können Sie jede Klasse übergeben, die die IList <Bar> -Schnittstelle implementiert. Wenn Sie stattdessen List <Bar> verwendet haben, konnte nur eine List <Bar> -Instanz übergeben werden.

Der IList <Bar> Weg ist lockerer gekoppelt als der List <Bar> Weg.

smack0007
quelle
13

Unter der Annahme, dass keine dieser Fragen (oder Antworten) zwischen Liste und IList den Signaturunterschied erwähnt. (Deshalb habe ich auf SO nach dieser Frage gesucht!)

Hier sind die in List enthaltenen Methoden, die zumindest ab .NET 4.5 (ca. 2015) nicht in IList enthalten sind.

  • AddRange
  • AsReadOnly
  • Binäre Suche
  • Kapazität
  • Konvertieren alle
  • Existiert
  • Finden
  • Finde alle
  • FindIndex
  • FindLast
  • FindLastIndex
  • Für jedes
  • GetRange
  • InsertRange
  • LastIndexOf
  • Alles entfernen
  • RemoveRange
  • Umkehren
  • Sortieren
  • ToArray
  • TrimExcess
  • TrueForAll
JasonS
quelle
1
Nicht ganz richtig. Reverseund ToArraysind Erweiterungsmethoden für die IEnumerable <T> -Schnittstelle, von der IList <T> abgeleitet ist.
Tarec
Das liegt daran, dass diese nur in Lists und nicht in anderen Implementierungen von sinnvoll sind IList.
HankCa
12

Der wichtigste Fall für die Verwendung von Schnittstellen über Implementierungen sind die Parameter Ihrer API. Wenn Ihre API einen List-Parameter verwendet, muss jeder, der ihn verwendet, List verwenden. Wenn der Parametertyp IList ist, hat der Aufrufer viel mehr Freiheit und kann Klassen verwenden, von denen Sie noch nie gehört haben, die möglicherweise nicht einmal vorhanden waren, als Ihr Code geschrieben wurde.

Michael Borgwardt
quelle
7

Was passiert , wenn .NET 5.0 ersetzt System.Collections.Generic.List<T>zu System.Collection.Generics.LinearList<T>. .NET besitzt immer den Namen, List<T>aber sie garantieren, dass IList<T>es sich um einen Vertrag handelt. Meiner Meinung nach sollten wir (zumindest ich) nicht den Namen einer Person verwenden (obwohl es in diesem Fall .NET ist) und später in Schwierigkeiten geraten.

Im Falle der Verwendung IList<T>wird dem Aufrufer immer garantiert, dass die Dinge funktionieren, und es steht dem Implementierer frei, die zugrunde liegende Sammlung in eine alternative konkrete Implementierung von zu ändernIList

Soundararajan
quelle
7

Grundsätzlich werden in den meisten der obigen Antworten alle Konzepte angegeben, warum die Schnittstelle über konkreten Implementierungen verwendet wird.

IList<T> defines those methods (not including extension methods)

IList<T> MSDN-Link

  1. Hinzufügen
  2. klar
  3. Enthält
  4. Kopieren nach
  5. GetEnumerator
  6. Index von
  7. Einfügen
  8. Entfernen
  9. RemoveAt

List<T> implementiert diese neun Methoden (ohne Erweiterungsmethoden), zusätzlich gibt es ungefähr 41 öffentliche Methoden, was Ihre Überlegung abwägt, welche in Ihrer Anwendung verwendet werden soll.

List<T> MSDN-Link

yantaq
quelle
4

Sie würden, weil das Definieren einer IList oder einer ICollection sich für andere Implementierungen Ihrer Schnittstellen öffnen würde.

Möglicherweise möchten Sie ein IOrderRepository haben, das eine Sammlung von Aufträgen in einer IList oder einer ICollection definiert. Sie können dann verschiedene Arten von Implementierungen verwenden, um eine Liste von Aufträgen bereitzustellen, sofern diese den von Ihrer IList oder ICollection definierten "Regeln" entsprechen.

Peter Lindholm
quelle
3

IList <> ist gemäß den Empfehlungen des anderen Posters fast immer vorzuziehen. Beachten Sie jedoch, dass in .NET 3.5 sp 1 ein Fehler vorliegt vorliegt, wenn eine IList <> mehr als einen Serialisierungs- / Deserialisierungszyklus mit dem WCF DataContractSerializer durchläuft.

Es gibt jetzt einen SP, um diesen Fehler zu beheben: KB 971030

StuartLC
quelle
2

Die Schnittstelle stellt sicher, dass Sie mindestens die Methoden erhalten, die Sie erwarten . Kenntnis der Definition der Schnittstelle, dh. Alle abstrakten Methoden, die von einer Klasse implementiert werden sollen, die die Schnittstelle erbt. Wenn also jemand eine große eigene Klasse mit mehreren Methoden außer den Methoden erstellt, die er von der Schnittstelle für einige zusätzliche Funktionen geerbt hat, und diese für Sie nicht von Nutzen sind, ist es besser, einen Verweis auf eine Unterklasse zu verwenden (in diesem Fall die Schnittstelle) und weisen ihm das konkrete Klassenobjekt zu.

Ein weiterer Vorteil besteht darin, dass Ihr Code vor Änderungen an der konkreten Klasse geschützt ist, da Sie nur einige der Methoden der konkreten Klasse abonnieren und diese Methoden vorhanden sein werden, solange die konkrete Klasse von der Schnittstelle erbt, die Sie sind mit. Dies ist die Sicherheit für Sie und die Freiheit für den Codierer, der eine konkrete Implementierung schreibt, um seine konkrete Klasse zu ändern oder um weitere Funktionen zu erweitern.

vishy
quelle
2

Sie können dieses Argument aus verschiedenen Blickwinkeln betrachten, einschließlich eines rein OO-Ansatzes, der besagt, dass das Programmieren gegen eine Schnittstelle keine Implementierung ist. Bei diesem Gedanken folgt die Verwendung von IList dem gleichen Prinzip wie die Weitergabe und Verwendung von Schnittstellen, die Sie von Grund auf neu definieren. Ich glaube auch an die Skalierbarkeits- und Flexibilitätsfaktoren, die eine Schnittstelle im Allgemeinen bietet. Wenn eine Klasse, die IList <T> implementiert, erweitert oder geändert werden muss, muss sich der konsumierende Code nicht ändern. es weiß, woran der IList Interface-Vertrag festhält. Die Verwendung einer konkreten Implementierung und List <T> für eine Klasse, die sich ändert, kann jedoch dazu führen, dass auch der aufrufende Code geändert werden muss. Dies liegt daran, dass eine Klasse, die IList <T> einhält, ein bestimmtes Verhalten garantiert, das von einem konkreten Typ mit List <T> nicht garantiert wird.

Die Möglichkeit, beispielsweise die Standardimplementierung von List <T> für eine Klasse zu implementieren, die IList <T> implementiert, z. B. .Add, .Remove oder eine andere IList-Methode, bietet dem Entwickler viel Flexibilität und Leistung, die ansonsten vordefiniert sind nach Liste <T>

atconway
quelle
0

In der Regel besteht ein guter Ansatz darin, IList in Ihrer öffentlich zugänglichen API zu verwenden (falls zutreffend, und Listensemantik ist erforderlich) und dann intern aufzulisten, um die API zu implementieren. Auf diese Weise können Sie zu einer anderen Implementierung von IList wechseln, ohne den Code zu beschädigen, der Ihre Klasse verwendet.

Die Klassennamenliste kann im nächsten .net-Framework geändert werden, aber die Schnittstelle wird sich nie ändern, da die Schnittstelle vertraglich gebunden ist.

Beachten Sie, dass Sie möglicherweise nur IEnumerable verfügbar machen möchten, wenn Ihre API nur in foreach-Schleifen usw. verwendet werden soll.

fauler Entwickler
quelle