Frage

Gibt es ein Problem mit IEnumerable<T> als Rückgabetyp verwenden? FxCop beschwert sich über die Rückkehr List<T> (es berät Collection<T> Rückkehr statt).

Nun, ich habe immer von der Regel leiten „nehmen die wenigsten können Sie, aber das Maximum zurück.“

Von diesem Standpunkt aus IEnumerable<T> Rückkehr ist eine schlechte Sache, aber was soll ich tun, wenn ich will „lazy retrieval“ benutzen? Auch das yield Schlüsselwort ist so ein Goodie.

War es hilfreich?

Lösung

Das ist wirklich eine zweiteilige Frage.

1) Gibt es von Natur aus etwas falsch mit einem IEnumerable Rückkehr

Kein gar nichts. In der Tat, wenn Sie C # Iteratoren verwenden, ist dies das erwartete Verhalten. Umwandlung in eine List oder eine andere Sammlung Klasse präventiv ist keine gute Idee. Dadurch ist eine Annahme über die Nutzungsmuster von Ihrem Anrufer zu machen. Ich finde, es ist keine gute Idee, etwas über den Anrufer zu übernehmen. Sie haben gute Gründe, warum sie eine IEnumerable wollen. Vielleicht wollen sie es auf eine ganz andere Sammlungshierarchie konvertieren (in diesem Fall eine Umstellung auf Liste verschwendet wird).

2) Gibt es Umstände, unter denen es vorteilhaft sein kann, etwas anderes als IEnumerable zurück ?

Ja. Während es keine gute Idee ist viel über Ihre Anrufer zu übernehmen, dann ist es vollkommen in Ordnung, Entscheidungen zu treffen, basierend auf Ihr eigenes Verhalten. Stellen Sie sich ein Szenario, wo Sie hatte eine Multi-Threaded-Objekt, das Anfragen in ein Objekt wurde Schlange stehen, die ständig aktualisiert wurde. In diesem Fall wird ein rohes IEnumerable Rückkehr ist unverantwortlich. Sobald die Sammlung der zählbare geändert wird, ist für ungültig erklärt und führt dazu, dass ein execption auftreten. Stattdessen könnten Sie eine Momentaufnahme der Struktur nehmen und diesen Wert zurück. Sagen Sie in einer Liste Form. In diesem Fall würde ich wieder nur das Objekt als direkte Struktur (oder Schnittstelle).

Dies ist sicherlich der seltenere Fall aber.

Andere Tipps

Nein, IEnumerable<T> ist ein gut , was hier zurückkehren, da alles, was Sie sind viel versprechend ist „eine Folge von (typisiert) Werte“. Ideal für LINQ usw. und perfekt geeignet.

Der Anrufer einfach diese Daten in eine Liste setzen kann (oder was auch immer.) - vor allem mit LINQ (ToList, ToArray usw.)

Dieser Ansatz ermöglicht es Ihnen, träge spulen Werte zurück, anstatt alle Daten puffern mit. Auf jeden Fall ein Goodie. Ich schrieb-up eine weitere nützliche IEnumerable<T> Trick den anderen Tag auch.

Über Ihr Prinzip:. „Nehmen die wenigsten können Sie, aber geben die maximale“

Der Schlüssel der Komplexität eines großen Programms zur Verwaltung ist eine Technik namens Information Hiding . Wenn Ihre Methode durch den Bau eines List<T> funktioniert, ist es oft nicht notwendig, diese Tatsache zu offenbaren durch diese Art der Rückkehr. Wenn Sie das tun, dann können Sie Ihre Anrufer ändern die Liste sie zurückkommen. Dadurch wird Ihre Fähigkeit, Caching, oder faul Iteration mit yield return zu tun.

So ein besseres Prinzip ist für eine Funktion zu folgen ist. „So wenig wie möglich zeigen, wie Sie arbeiten“

IEnumerable ist für mich in Ordnung, aber es hat einige Nachteile. Der Kunde hat auflisten, um die Ergebnisse zu erhalten. Es hat keine Möglichkeit für die Grafen zu überprüfen usw. Liste ist schlecht, weil Sie zu viel Kontrolle aussetzen; der Kunde kann hinzufügen / entfernen usw. daraus und das kann eine schlechte Sache sein. Sammlung scheint die beste compromomise, zumindest in FxCop Sicht. Ich benutze Allways was sachgemäßer in meinem Zusammenhang scheint (z. B. wenn ich i-Sammlung als Rückgabetyp belichten eine Nur-Lese-Sammlung zurückkehren will und das Rück List.AsReadOnly () oder IEnumerable für faule Auswertung durch Ertrag etc.). Nehmen Sie sich auf einem von Fall zu Fall

„nehmen die wenigsten können Sie, aber kehrt das Maximum“ ist das, was ich befürworten. Wenn eine Methode ein Objekt zurückgibt, welche Begründungen müssen wir nicht den tatsächlichen Typ zurückzukehren und die Fähigkeiten des Objekts begrenzen, indem Sie einen Basistyp zurück. Dies wirft jedoch eine Frage, wie können wir wissen, was das „Maximum“ (Ist-Typ) sein wird, wenn wir eine Schnittstelle entwerfen. Die Antwort ist sehr einfach. Nur in extremen Fällen, in denen die Interface-Designer eine offene Schnittstelle sind die Gestaltung, die außerhalb der Anwendung / Komponente umgesetzt werden, würden sie nicht wissen, was der tatsächliche Rückgabetyp sein kann. Ein Smart-Designer sollte immer überlegen, was das Verfahren tun sollte und was für ein optimales / generic Rückgabetyp sollte.

z. Wenn ich eine Schnittstelle bin der Gestaltung eines Vektors von Objekten abzurufen, und ich weiß, dass die Anzahl der zurückgegebenen Objekte werden variabel sein, werde ich immer ein kluger Entwickler davon ausgehen, wird immer eine Liste verwenden. Wenn jemand ein Array zurückgeben will, würde ich seine Fähigkeiten in Frage stellen, es sei denn, er / sie ist nur die Daten aus einer anderen Ebene zurückkehrt, die er / sie nicht besitzt. Und das ist wahrscheinlich, warum befürwortet FxCop für ICollection (gemeinsame Basis für List und Array).

Das Gesagte wird, gibt es einige andere Dinge zu beachten

  • , wenn die zurückgegebenen Daten sollten wandelbar oder unveränderlich sein

  • Wenn die zurückgegebenen Daten auf mehrere Anrufer geteilt werden

Im Hinblick auf die LINQ Lazy Evaluation Ich bin sicher, 95% + C # Benutzer nicht verstehen, die intestacies. Es ist so nicht-oo-ish. OO fördert konkrete Zustandsänderungen auf Methodenaufrufe. LINQ faul Auswertung fördert Veränderungen Laufzeitstatus auf Ausdrucksauswertung Muster (nicht etwas Nicht-erfahrene Benutzer immer folgen).

Rückkehr IEnumerable ist in Ordnung, wenn Sie wirklich sind nur eine Aufzählung der Rückkehr, und es wird von Ihrem Anrufer als solches konsumiert werden.

Aber wie andere darauf hin, hat es den Nachteil, dass der Anrufer muss möglicherweise aufzuzählen, wenn er andere Informationen benötigt (zum Beispiel Count). Die .NET 3.5 Extension-Methode IEnumerable .Count hinter den Kulissen aufzählen, wenn der Rückgabewert nicht ICollection implementieren, was unerwünscht sein kann.

ich oft zurückkehren IList oder ICollection , wenn das Ergebnis ist eine Sammlung - intern Ihre Methode eine Liste verwenden kann und entweder zurückgeben, wie sie ist, oder Rückkehr List .AsReadOnly, wenn Sie wollen vor Veränderungen schützen (zB wenn Sie die Liste intern sind Caching). AFAIK FxCop ist recht zufrieden mit entweder davon.

Ein wichtiger Aspekt ist, dass, wenn Sie eine List<T> kehren Sie tatsächlich sind eine Referenz Rückkehr . Das macht es möglich, dass ein Anrufer Ihre Liste zu bearbeiten. Dies ist ein häufiges Problem-zum Beispiel eine Business-Schicht, die eine List<T> auf eine GUI-Schicht zurück.

Nur weil Sie sagen, du bist der Rückkehr IEnumerable bedeutet nicht, Sie eine Liste nicht zurückkehren kann. Die Idee ist, nicht benötigte Kopplung zu reduzieren. Alles, was der Anrufer über sollte kümmern wird eine Liste der Dinge bekommen, anstatt die genaue Art der Sammlung verwendet diese Liste enthalten. Wenn Sie etwas haben, das durch ein Array gesichert ist, dann immer so etwas wie Count geht sowieso schnell sein.

Ich denke, Ihre eigene Führung ist groß - wenn Sie in der Lage sind, über spezifischere zu sein, was Sie ohne Leistungseinbußen sind Rückkehr (Sie müssen nicht zum Beispiel auf eine Liste aus Ihrem Ergebnis bauen), dazu. Aber wenn Ihre Funktion berechtigterweise nicht weiß, welche Art es geht zu finden, wie wenn in einigen Situationen werden Sie mit einer Liste arbeiten und in einigen mit einem Array, usw., dann Rückkehr IEnumerable ist die „beste“ Sie tun können, . Betrachten Sie es als „größte gemeinsame Vielfache“ alles, was Sie wollen, könnten zurückkehren.

Ich kann die gewählte Antwort akzeptieren. Es gibt Möglichkeiten, mit dem Szenario beschrieben tun, sondern mit einer Liste oder was auch immer Ihre Verwendung ist nicht einer von ihnen. Der Moment der IEnumerable zurückgegeben Sie davon ausgehen müssen, dass der Anrufer könnte eine foreach tun. In diesem Fall spielt es keine Rolle, ob die konkrete Art Liste oder Spaghetti ist. In der Tat nur die Indizierung ist ein Problem, vor allem, wenn Elementen entfernt werden.

Jeder zurückgegebene Wert ist eine Momentaufnahme. Es kann der aktuelle Inhalt des IEnumerable sein, in dem Fall, wenn es zwischengespeichert wird es ein Klon der Cache-Kopie sein sollte; wenn es soll mehr dynamisch sein (wie die resuts einer SQL-Abfrage), dann yield return verwenden; jedoch mit dem der Container nach Belieben und liefern Methoden wie Graf und Indexer mutieren, ist ein Rezept für eine Katastrophe in einer Multi-Thread-Welt. Ich habe auch nicht in die Fähigkeit des Anrufers bekommen rufen auf einem Container hinzufügen oder löschen Sie den Code soll unter Kontrolle sein.

Rückkehr auch ein konkretes Schlosses Sie in eine Implementierung. Heute intern können Sie eine Liste verwenden. Morgen vielleicht wird man multithreaded und wollen einen Thread sicheren Behälter verwenden oder ein Array oder eine Warteschlange oder die Werte Sammlung eines Wörterbuchs oder die Ausgabe einer Linq-Abfrage. Wenn Sie sich in einem konkreten Rückgabetyp sperren, dann müssen Sie entweder eine Reihe von Code ändern oder eine Konvertierungen vor der Rückkehr.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top