2012-04-16 8 views
5

Mögliche Duplizieren:
Collection<T> versus List<T> what should you use on your interfaces?OK, um eine interne Liste <T> als IEnumerable <T> oder ICollection <T> zurückzugeben?

Betrachten wir diese Methode-der zurückgegebene Variable myVar ist ein List<T>, aber die Rückgabetyp der Methode MyMethod() ist ein IEnumerable<T>:

public IEnumerable<T> MyMethod(string stuff) 
{ 
    var myVar = new List<T>(); 
    //do stuff 

    return myVar; 
} 

Im Wesentlichen möchte ich wissen, ob returni ng myVar als ein anderer Typ ist in Ordnung.

Speziell in Bezug auf meine Situation geht das "Do-Zeug" durch eine DataRow und ordnet die Objekte in dieser DataRow einer Liste von Objekten. Ich habe auch ähnliche Situationen mit ICollection und IList Rückgabetypen an anderen Orten.

Der Grund, warum ich entweder IEnumerable oder ICollection zurückgeben möchte, ist so, dass ich nicht mehr zurückgebe als nötig. Gleichzeitig kann der Aufrufer den zurückgegebenen Wert jedoch in einen List konvertieren, wenn dies erforderlich ist.

Allerdings scheint es komisch, dass meine Return-Anweisung eine List zurückgibt, anstatt, was der Rückgabetyp der Methode ist. Ist das normal? Ist etwas falsch daran, dies zu tun?

Klärung (als Reaktion auf die Betrogene Kommentare):

Nur um zu klären, was ich neugierig bin im Begriff ist, ob es in Ordnung ist, dass meine return-Anweisung im Körper ein List<T> zurückkehrt, aber die Methode Header hat einen Rückgabetyp von IEnumerable, oder möglicherweise ICollection, Collection, etc ... Etwas verschiedene als als Körper zurück Anweisung.

+2

Der Aufrufer sollte nie von IEnumerable zu List konvertieren. Der Grund dafür, dass eine Schnittstelle zurückgegeben wird, ist, dass es keine Rolle spielt, ob es eine zugrunde liegende Liste, eine überlagerbare Sammlung, ein einfaches Array oder sogar eine Liste über die Rendite gibt. – aqwert

+1

Die beiden vorgeschlagenen Betrogenen sind Duplikern näher als diese Frage, denke ich, obwohl sie alle eng miteinander verwandt sind. –

+0

@ChrisCharabaruk Ich stimme zu, dass diese Frage kein Duplikat ist und ich habe sie überarbeitet, um hoffentlich besser zu vermitteln, was ich glaube, dass sie einzigartig ist. Ich habe auch dafür gestimmt, die Frage erneut zu stellen. – DavidRR

Antwort

6

Nicht nur daran ist nichts falsch, aber es ist wirklich eine gute Übung: bloß das unbedingt Notwendige bloßlegen. Auf diese Weise kann sich der Aufrufer nicht darauf verlassen, dass die Methode eine List<T> zurückgibt. Wenn Sie die Implementierung aus irgendeinem Grund ändern müssen, um etwas anderes zurückzugeben, werden Sie Ihren Vertrag nicht brechen. Allerdings kann der aufrufende Code brechen, wenn er (fälschlicherweise) Annahmen darüber gemacht hat, was die Methode tatsächlich zurückgibt.

+0

".... und der Anrufer kann es in eine Liste konvertieren, wenn es" klingt, dass dies bereits beabsichtigt ist, noch gute Praxis? –

+0

@TimSchmelter, nun, wenn der Aufrufer * soll * wissen soll, dass die Methode eine Liste zurückgibt, dann sollte der Rückgabetyp natürlich List sein ... Es ist nicht einmal eine Frage der guten Praxis, nur eine Frage des gesunden Menschenverstandes ;) –

+0

Also, um zu überprüfen, gibt meine Rückgabeanweisung eine Liste zurück, aber der Rückgabetyp der Methode ist IEnumerable , das ist in Ordnung? – RJP

2

Es ist nichts falsch daran.

Die tatsächlich zurückkehrende konkrete Klasse ist die einzige Möglichkeit, die "Rückkehrschnittstelle" -Anforderung zu erfüllen.

Es könnte Nachteile haben, wenn Sie das Wissen bestimmter Klassen in den Anrufcode eingeben (List<T> r = (List<T>)MyMethod("ff")). Aber wenn Sie das Ergebnis als Schnittstelle behandeln (wie Sie es erwarten), ist es in Ordnung.

3

Der Grund für die Rückgabe des IEnumerable<T> Typs ist, dass der Aufrufer die Liste nicht ändern kann (ohne sie in eine Liste zurückzuversetzen). Wenn Sie alle (die meisten?) Bemerken, nehmen die Erweiterungsmethoden das Argument IEnumerable<T> an, damit Sie wissen, dass die Erweiterungsmethode Ihre Liste nicht ändert.

Zweitens erbt List<T> von IEnumerable<T>.

Edit: Wie Thomas in einem Kommentar erklärt, dass die IEnumerable<T> durch den Anrufer an einen List<T> und modifiziert zurückgeworfen werden könnte. Wenn es Ihr Hauptziel ist, es schreibgeschützt zu machen, können Sie die Liste als myVar.AsReadOnly() zurückgeben.Aber dann ist der Typ ReadOnlyCollection<T>.

+0

Nicht sicher, ob das Verhindern von Änderungen der Hauptgrund ist – zerkms

+1

Es wird nicht verhindert, dass der Aufrufer die Liste ändert: Der aufrufende Code kann das Ergebnis immer noch in Liste umwandeln. Dies bedeutet jedoch, dass undokumentierte Annahmen über die Implementierung gemacht werden, so dass es bei einer Änderung der Implementierung zu Problemen kommen kann. –

+0

Und die Rückgabe einer 'ReadOnlyCollection ' behält die Array-Semantik des zurückgegebenen Werts. Das heißt, ein Element kann mit seinem ganzzahligen Index abgerufen werden. Und dass eine Anzahl der Elemente in der Auflistung verfügbar ist, ohne dass die Auflistung durchlaufen werden muss. – DavidRR

1

Ich denke, das ist nicht optimal, da es den Anrufer ermöglicht, auf List<T> zu werfen, die auf einem Implementierungsdetail beruht. Ich würde eine Art Maskierung hinzufügen, z. B. Select(x=>x).

Ein dynamisch typisierter Anrufer bemerkt möglicherweise nicht einmal, dass Sie Ihre Liste in IEnumerable<T> umwandeln. Für ihn ist es einfach List<T>.

Die Rückgabe einer internen permanenten List<T> als IEnumerable<T> wäre sehr falsch, da es dem Anrufer erlaubt, den internen Zustand Ihrer Klasse zu ändern. Da Sie jedoch bei jedem Aufruf eine neue Instanz von List<T> zurückgeben, die nirgendwo anders verwendet wird, gilt dieses Argument in Ihrem Beispiel nicht.

+0

Wenn Sie auf diese Weise gehen möchten, können Sie auch einen Iterator verwenden;) –

+0

Das Einpacken der Liste in etwas fügt unnötiges Laufzeitgepäck hinzu. Aber vielleicht könnte man eine 'Liste '99 mal von 100 zurückgeben und nur gelegentlich einen Wrapper zurückgeben? Das würde Code brechen, der zu "List" führt, aber die Leistung nicht zu sehr schadet. – supercat

+0

@supercat Da für 99% des Codes dieser kleine Overhead keine Rolle spielt, würde ich mich nur darum kümmern, wenn mein Profiling aussagt, dass es signifikant ist. – CodesInChaos

Verwandte Themen