Normalerweise finde ich etwas wie:
%Vor%und ich finde all diese Verwechslung von Typen / Interface ein wenig verwirrend und es kitzelt meine potentielle Performance-Problem-Antenne (die ich natürlich bis zum erwiesenen Recht ignoriere).
Ist das idiomatische und korrekte C # oder gibt es eine bessere Alternative, um das Hin und Her zu vermeiden, um auf die richtigen Methoden zum Arbeiten mit den Daten zugreifen zu können?
BEARBEITEN: Die Frage ist eigentlich zweifach:
Wann ist es richtig, entweder die IEnumerable-Schnittstelle oder ein Array oder eine Liste (oder einen anderen IEnumerable-Implementierungstyp) direkt zu verwenden (wenn Parameter akzeptiert werden)?
Sollten Sie frei zwischen IEnumerables (Implementierung unbekannt) und Listen und IEnumerables und Arrays und Arrays und Listen wechseln oder ist das nicht idiomatisch (es gibt bessere Möglichkeiten, dies zu tun) / nicht performant (nicht typischerweise relevant, aber möglicherweise in einigen Fällen) / einfach nur hässlich (nicht mischbar, unlesbar)?
In Bezug auf die Leistung ...
In Bezug auf Idiome ...
Im Allgemeinen ist IEnumerable nützlich für öffentliche Eigenschaften, Funktionsparameter und oft für Rückgabewerte - und nur, wenn Sie wissen, dass Sie die Werte der Reihe nach verwenden werden.
Wenn Sie beispielsweise eine Funktion PrintValues hätten, wenn sie als PrintValues (List & lt; T & gt; -Werte) geschrieben wäre, wäre sie nur in der Lage, mit Listenwerten umzugehen, so dass der Benutzer zum Beispiel zuerst konvertieren müsste Sie benutzten ein T []. Ebenso mit, wenn die Funktion PrintValues (T [] Werte) war. Aber wenn es PrintValues (IEnumerable & lt; T & gt; -Werte) wäre, wäre es in der Lage, mit Listen, T [] s, Stapeln, Hashtabellen, Wörterbüchern, Zeichenketten, Mengen usw. umzugehen - jede Sammlung, die IEnumerable implementiert Sammlung.
In Bezug auf den internen Gebrauch ...
Beachten Sie auch, dass sich das Casting von der Verwendung von ToArray () oder ToList () unterscheidet. Letzteres beinhaltet das Kopieren der Werte, was in der Tat ein Performance- und Speicher-Hit ist, wenn Sie viele Elemente haben. Der erste ist einfach zu sagen: "Ein Hund ist ein Tier, so wie jedes Tier, kann es essen" (niedergeschlagen) oder "Dieses Tier ist zufällig ein Hund, so kann es bellen" (upcast). Ebenso sind alle Listen und T [] s IEnumerables, aber nur einige IEnumerables sind Listen oder T [] s.
Eine gute Faustregel ist, dass immer IEnumerable verwendet (wenn Sie Ihre Variablen / Methodenparameter / Methoden Rückgabetypen / Eigenschaften / etc. deklarieren), es sei denn, Sie haben einen guten Grund, dies nicht zu tun. Bei weitem die meisten Typ-kompatibel mit anderen (vor allem Erweiterung) Methoden.
Nun, Sie haben zwei Äpfel und eine Orange, die Sie vergleichen.
Die zwei Äpfel sind das Array und die Liste.
Ein Array in C # ist ein Array im C-Stil, in das eine Garbage-Collection integriert ist. Die Vorteile bei der Verwendung sind, dass sie sehr wenig Overhead haben, vorausgesetzt, Sie müssen die Dinge nicht verschieben. Das Schlimme ist, dass sie nicht so effizient sind, wenn du Dinge hinzufügst, Dinge entfernst und das Array auf andere Weise veränderst, während Speicher herumgeschoben wird.
Eine Liste ist ein dynamisches Array im C # -Stil (ähnlich der Klasse Vektor & lt; & gt; in C ++). Es gibt mehr Overhead, aber sie sind effizienter, wenn Sie Dinge viel bewegen müssen, da sie nicht versuchen, die Speichernutzung zusammenhängend zu halten.
Der beste Vergleich, den ich geben könnte, ist zu sagen, dass Arrays Listen sind, wie Strings zu StringBuilders sind.
Die Orange ist "IEnumerable". Dies ist kein Datentyp, sondern eine Schnittstelle. Wenn eine Klasse die IEnumerable-Schnittstelle implementiert, kann dieses Objekt in einer foreach () - Schleife verwendet werden.
Wenn Sie die Liste zurückgeben (wie in Ihrem Beispiel), wurde die Liste nicht in eine IEnumerable konvertiert. Eine Liste ist bereits ein IEnumerable-Objekt.
EDIT: Wann zwischen den zwei zu konvertieren:
Es hängt von der Anwendung ab. Es gibt sehr wenig, was mit einem Array getan werden kann, das mit einer Liste nicht möglich ist, daher würde ich die Liste generell empfehlen. Wahrscheinlich ist es das Beste, eine Designentscheidung zu treffen, dass Sie das eine oder das andere verwenden werden, so dass Sie nicht zwischen den beiden wechseln müssen. Wenn Sie sich auf eine externe Bibliothek verlassen, sollten Sie sie abstrahieren, um eine konsistente Nutzung zu gewährleisten.
Hoffe, das löscht ein bisschen vom Nebel.
Sieht so aus, als ob das Problem darin besteht, dass Sie sich nicht die Mühe gemacht haben, zu lernen, wie man ein Array sucht. Hinweis: Array.IndexOf oder Array.BinarySearch abhängig davon, ob das Array sortiert ist.
Sie haben Recht, dass das Konvertieren in eine Liste eine schlechte Idee ist: Sie verschwendet Speicherplatz und Zeit und macht den Code weniger lesbar. Blindes Upcasting auf IEnumerable
verlangsamt den Prozess und verhindert auch die Verwendung bestimmter Algorithmen (z. B. binäre Suche).
Ich versuche zu vermeiden, schnell zwischen Datentypen zu springen, wenn es vermieden werden kann.
Es muss der Fall sein, dass jede Situation, die der von Ihnen beschriebenen ähnlich ist, ausreichend verschieden ist, um eine dogmatische Regel bezüglich der Umwandlung Ihrer Typen zu verhindern; Es empfiehlt sich jedoch, eine Datenstruktur auszuwählen, die die von Ihnen benötigte Schnittstelle bestmöglich bereitstellt, ohne Elemente unnötig in neue Datenstrukturen kopieren zu müssen.Wann soll was verwendet werden?
Ich würde vorschlagen, den spezifischsten Typ zurückzugeben und den flexibelsten Typ zu verwenden.
So:
%Vor% Auf diese Weise können Sie Methoden auf List< T >
aufrufen, unabhängig davon, was Sie von der Methode zurückerhalten, zusätzlich zur Behandlung als IEnumerable. Verwenden Sie die Eingaben so flexibel wie möglich, damit Sie den Benutzern Ihrer Methode nicht vorschreiben, welche Art von Sammlung erstellt werden soll.
Sie haben Recht, die "Performance-Problem" -Antennen zu ignorieren, bis Sie tatsächlich ein Leistungsproblem haben. Die meisten Leistungsprobleme kommen von zu vielen I / O oder zu viel Sperren oder einer von ihnen falsch, und keiner von diesen trifft auf diese Frage zu.
Mein allgemeiner Ansatz ist:
Korollar zu # 4: keine Angst vor ToList () haben. ToList () ist dein Freund. Es erzwingt das IEnumerable & lt; T & gt; dann richtig bewerten (nützlich, wenn Sie mehrere where-Klauseln übereinander legen). Machen Sie sich nicht verrückt damit, aber fühlen Sie sich frei, es zu nennen, sobald Sie Ihre vollständige where-Klausel aufgebaut haben, bevor Sie die foreach darüber (oder dergleichen) machen.
Das ist natürlich nur eine grobe Richtlinie. Versuchen Sie einfach, das gleiche Muster in der gleichen Codebasis zu verwenden - Code-Stile, die herumspringen, machen es für Wartungs-Programmierer schwieriger, in Ihre Stimmung zu kommen.
Tags und Links c# idioms ienumerable