Wenn ich meine DAL oder einen anderen Code schreibe, der eine Reihe von Elementen zurückgibt, sollte ich immer meine return-Erklärung abgeben:
public IEnumerable<FooBar> GetRecentItems()
oder
public IList<FooBar> GetRecentItems()
Derzeit habe ich in meinem Code versucht, IEnumerable so oft wie möglich zu verwenden, bin mir aber nicht sicher, ob dies die beste Vorgehensweise ist? Es schien richtig zu sein, weil ich den allgemeinsten Datentyp zurückgab, während ich immer noch beschrieb, was er tut, aber vielleicht ist dies nicht richtig.
c#
ienumerable
KingNestor
quelle
quelle
Antworten:
Es hängt wirklich davon ab, warum Sie diese spezielle Schnittstelle verwenden.
Hat zum Beispiel
IList<T>
mehrere Methoden, die in nicht vorhanden sindIEnumerable<T>
:IndexOf(T item)
Insert(int index, T item)
RemoveAt(int index)
und Eigenschaften:
T this[int index] { get; set; }
Wenn Sie diese Methoden in irgendeiner Weise benötigen, kehren Sie auf jeden Fall zurück
IList<T>
.Wenn die Methode, die IhrIEnumerable<T>
Ergebnis verwendet, eine erwartetIList<T>
, wird die CLR vor der Berücksichtigung der erforderlichen Konvertierungen bewahrt, wodurch der kompilierte Code optimiert wird.quelle
Richtlinien für das Framework-Design empfehlen die Verwendung der Klasse Collection, wenn Sie eine Collection zurückgeben müssen, die vom Aufrufer oder ReadOnlyCollection für schreibgeschützte Sammlungen geändert werden kann.
Der Grund, warum dies einem einfachen vorgezogen wird,
IList
ist, dassIList
der Anrufer nicht informiert wird, ob er schreibgeschützt ist oder nicht.Wenn Sie
IEnumerable<T>
stattdessen eine zurückgeben, kann es für den Anrufer etwas schwieriger sein, bestimmte Vorgänge auszuführen. Außerdem geben Sie dem Anrufer nicht mehr die Flexibilität, die Sammlung zu ändern, was Sie möglicherweise möchten oder nicht.Beachten Sie, dass LINQ einige Tricks enthält und bestimmte Anrufe basierend auf dem Typ, für den sie ausgeführt werden, optimiert. Wenn Sie beispielsweise eine ausführen
Count
und die zugrunde liegende Sammlung eine Liste ist, werden NICHT alle Elemente durchlaufen.Persönlich würde ich mich für ein ORM wahrscheinlich an
Collection<T>
meinen Rückgabewert halten.quelle
Im Allgemeinen sollten Sie das allgemeinste benötigen und das spezifischste zurückgeben, das Sie können. Wenn Sie also eine Methode haben, die einen Parameter akzeptiert, und nur das benötigen, was in IEnumerable verfügbar ist, sollte dies Ihr Parametertyp sein. Wenn Ihre Methode entweder eine IList oder eine IEnumerable zurückgeben könnte, ziehen Sie es vor, IList zurückzugeben. Dies stellt sicher, dass es für die unterschiedlichsten Verbraucher nutzbar ist.
Seien Sie locker in dem, was Sie benötigen, und explizit in dem, was Sie bereitstellen.
quelle
Kommt darauf an...
Wenn Sie den am wenigsten abgeleiteten Typ (
IEnumerable
) zurückgeben, haben Sie den größten Spielraum, um die zugrunde liegende Implementierung später zu ändern.Durch die Rückgabe eines stärker abgeleiteten Typs (
IList
) erhalten die Benutzer Ihrer API mehr Operationen für das Ergebnis.Ich würde immer empfehlen, den am wenigsten abgeleiteten Typ zurückzugeben, der alle Operationen enthält, die Ihre Benutzer benötigen. Grundsätzlich müssen Sie also zunächst festlegen, welche Operationen für das Ergebnis im Kontext der von Ihnen definierten API sinnvoll sind.
quelle
Wenn Sie eine LINQ-Anweisung mit verzögerter Ausführung verwenden, um Ihre zu generieren
IEnumerable<T>
, bedeutet ein Aufruf,.ToList()
bevor Sie von Ihrer Methode zurückkehren, dass Ihre Elemente möglicherweise zweimal wiederholt werden - einmal, um die Liste zu erstellen, und einmal, wenn der Aufrufer eine Schleife durchläuft , filtert oder transformiert Ihren Rückgabewert. Wenn es praktisch ist, möchte ich vermeiden, die Ergebnisse von LINQ-to-Objects in eine konkrete Liste oder ein konkretes Wörterbuch zu konvertieren, bis ich muss. Wenn mein Anrufer eine Liste benötigt, ist dies nur ein einfacher Methodenaufruf - ich muss diese Entscheidung nicht für ihn treffen, und das macht meinen Code in den Fällen, in denen der Anrufer nur einen Foreach ausführt, etwas effizienter.quelle
List<T>
bietet dem aufrufenden Code viele weitere Funktionen, z. B. das Ändern des zurückgegebenen Objekts und den Zugriff über den Index. Die Frage lautet also: Wollen Sie im spezifischen Anwendungsfall Ihrer Anwendung solche Verwendungen unterstützen (vermutlich durch Rückgabe einer frisch erstellten Sammlung!), Um es dem Anrufer bequem zu machen - oder möchten Sie Geschwindigkeit für den einfachen Fall, wenn alle Der Anrufer muss die Sammlung durchlaufen und Sie können sicher einen Verweis auf eine echte zugrunde liegende Sammlung zurückgeben, ohne befürchten zu müssen, dass diese fälschlicherweise geändert wird usw.?Nur Sie können diese Frage beantworten, und nur wenn Sie genau wissen, was Ihre Anrufer mit dem Rückgabewert tun möchten und wie wichtig die Leistung hier ist (wie groß sind die Sammlungen, die Sie kopieren würden, wie wahrscheinlich ist dies ein Engpass). etc).
quelle
Wenn die Sammlung schreibgeschützt sein soll oder die Änderung der Sammlung von der gesteuert wird, ist es keine gute Idee,
Parent
einIList
Just for zurückzugebenCount
.In Linq gibt es eine
Count()
Erweiterungsmethode, beiIEnumerable<T>
der innerhalb der CLR eine Verknüpfung hergestellt wird,.Count
wenn der zugrunde liegende Typ vorliegtIList
, sodass der Leistungsunterschied vernachlässigbar ist.Im Allgemeinen halte ich es für eine bessere Praxis, IEnumerable zurückzugeben, wenn dies erforderlich ist. Wenn Sie Ergänzungen vornehmen müssen, fügen Sie diese Methoden der übergeordneten Klasse hinzu. Andernfalls verwaltet der Verbraucher die Sammlung innerhalb von Model, was gegen die Prinzipien
manufacturer.Models.Add(model)
verstößt , z. B. gegen das Gesetz von demeter. Natürlich sind dies nur Richtlinien und keine festen Regeln, aber bis Sie die Anwendbarkeit vollständig verstanden haben, ist es besser, blind zu folgen, als überhaupt nicht zu folgen.(Hinweis: Wenn Sie nNHibernate verwenden, müssen Sie möglicherweise eine private IList mit verschiedenen Accessoren zuordnen.)
quelle
Es ist nicht so einfach, wenn Sie von Rückgabewerten anstelle von Eingabeparametern sprechen. Wenn es sich um einen Eingabeparameter handelt, wissen Sie genau, was Sie tun müssen. Wenn Sie also in der Lage sein müssen, über die Sammlung zu iterieren, verwenden Sie eine IE-Nummer, während Sie beim Hinzufügen oder Entfernen eine IList verwenden.
Bei einem Rückgabewert ist es schwieriger. Was erwartet Ihr Anrufer? Wenn Sie eine IEnumerable zurückgeben, weiß er a priori nicht, dass er daraus eine IList machen kann. Wenn Sie jedoch einen IList zurückgeben, weiß er, dass er darüber iterieren kann. Sie müssen also berücksichtigen, was Ihr Anrufer mit den Daten tun wird. Die Funktionalität, die Ihr Anrufer benötigt / erwartet, sollte bei der Entscheidung über die Rückgabe maßgeblich sein.
quelle
Wie alle gesagt haben, hängt es davon ab, ob Sie keine Funktion zum Hinzufügen / Entfernen auf der aufrufenden Ebene hinzufügen möchten, dann werde ich für IEnumerable stimmen, da es nur Iteration und grundlegende Funktionen bietet, die mir in der Design-Perspektive gefallen. Zurück IList meine Stimmen sind immer wieder dagegen, aber es ist hauptsächlich das, was du magst und was nicht. In Bezug auf die Leistung denke ich, dass sie mehr gleich sind.
quelle
Wenn Sie in Ihrem externen Code nicht zählen, ist es immer besser, IEnumerable zurückzugeben, da Sie später Ihre Implementierung ändern können (ohne Auswirkungen auf den externen Code), um beispielsweise Iteratorlogik zu erzielen und Speicherressourcen zu sparen (übrigens sehr gute Sprachfunktion) ).
Wenn Sie jedoch die Anzahl der Elemente benötigen, vergessen Sie nicht, dass zwischen IEnumerable und IList - ICollection eine weitere Ebene liegt .
quelle
Ich bin vielleicht ein bisschen daneben, da niemand es bisher vorgeschlagen hat, aber warum gibst du keine zurück
(I)Collection<T>
?Soweit ich mich erinnere,
Collection<T>
war der bevorzugte Rückgabetyp dem,List<T>
weil er die Implementierung abstrahiert. Sie alle implementierenIEnumerable
, aber das klingt für mich etwas zu niedrig für den Job.quelle
Ich denke, Sie können beide verwenden, aber jeder hat eine Verwendung. Grundsätzlich
List
istIEnumerable
aber Sie haben Zählfunktion, Element hinzufügen, Element entfernenIEnumerable
ist nicht effizient zum Zählen von Elementen oder zum Abrufen eines bestimmten Elements in der Sammlung.List
ist eine Sammlung, die sich ideal zum Auffinden bestimmter Elemente, zum einfachen Hinzufügen oder Entfernen von Elementen eignet.Im Allgemeinen versuche ich,
List
wenn möglich zu verwenden , da dies mir mehr Flexibilität gibt.Verwenden Sie
List<FooBar> getRecentItems()
eher alsIList<FooBar> GetRecentItems()
quelle
Ich denke, die allgemeine Regel ist, die spezifischere Klasse zu verwenden, um zurückzukehren, unnötige Arbeit zu vermeiden und Ihrem Anrufer mehr Optionen zu geben.
Trotzdem denke ich, dass es wichtiger ist, den Code vor Ihnen zu berücksichtigen, den Sie schreiben, als den Code, den der nächste Typ schreiben wird (im Rahmen der Vernunft). Dies liegt daran, dass Sie Annahmen über den bereits vorhandenen Code treffen können.
Denken Sie daran, dass das Verschieben nach UP zu einer Sammlung von IEnumerable in einer Schnittstelle funktioniert. Wenn Sie von einer Sammlung nach IEnumerable wechseln, wird der vorhandene Code beschädigt.
Wenn diese Meinungen alle widersprüchlich erscheinen, liegt dies daran, dass die Entscheidung subjektiv ist.
quelle
TL; DR; - Zusammenfassung
List
) für die Rückgabewerte und den allgemeinsten Typ für Eingabeparameter, auch bei Sammlungen.IReadOnlyList
oderIReadOnlyCollection
als Rückgabewerttyp verwenden.Mehr
quelle