Ich möchte in LINQ das Gleiche tun, aber ich kann nicht herausfinden, wie:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
Was ist die wahre Syntax?
linq
foreach
ienumerable
tags2k
quelle
quelle
ForEach()
.ForEach
Erweiterung .foreach (var i in items) i.Dostuff();
Antworten:
Es gibt keine ForEach-Erweiterung für
IEnumerable
; nur fürList<T>
. Also könntest du es tunAlternativ können Sie auch Ihre eigene ForEach-Erweiterungsmethode schreiben:
quelle
IENumerable<T>
in der Erweiterungsmethode zurückgeben. Wie:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Fredrik hat das Update bereitgestellt, aber es kann sich lohnen, darüber nachzudenken, warum dies zunächst nicht im Framework enthalten ist. Ich glaube, die Idee ist, dass die LINQ-Abfrageoperatoren nebenwirkungsfrei sein und zu einer einigermaßen funktionalen Sichtweise auf die Welt passen sollten. ForEach ist eindeutig genau das Gegenteil - ein Konstrukt, das ausschließlich auf Nebenwirkungen basiert.
Das heißt nicht, dass dies eine schlechte Sache ist - nur über die philosophischen Gründe für die Entscheidung nachzudenken.
quelle
Seq.iter
gibt nichts zurück, geschweige denn eine neue Sequenz mit Nebenwirkungen. Es geht wirklich nur um Nebenwirkungen. Sie denken vielleicht daranSeq.map
, weilSeq.iter
es genau einerForEach
Erweiterungsmethode auf entsprichtIEnumerabe<_>
.Update 17.07.2012: Anscheinend wurde ab C # 5.0 das
foreach
unten beschriebene Verhalten geändert und " die Verwendung einerforeach
Iterationsvariablen in einem verschachtelten Lambda-Ausdruck führt nicht mehr zu unerwarteten Ergebnissen. " Diese Antwort gilt nicht für C # ≥ 5.0 .@ John Skeet und alle, die das Schlüsselwort foreach bevorzugen.
Das Problem mit "foreach" in C # vor 5.0 ist, dass es nicht mit der Funktionsweise des Äquivalents "für das Verständnis" in anderen Sprachen übereinstimmt und mit der Art und Weise, wie ich es erwarten würde (persönliche Meinung hier nur, weil andere ihre erwähnt haben Meinung zur Lesbarkeit). Siehe alle Fragen zu " Zugriff auf modifizierten Abschluss " sowie " Schließen über die als schädlich geltende Schleifenvariable ". Dies ist nur "schädlich", da "foreach" in C # implementiert ist.
Nehmen Sie die folgenden Beispiele mit der funktional äquivalenten Erweiterungsmethode, die der Antwort von @Fredrik Kalseth entspricht.
Entschuldigung für das übermäßig erfundene Beispiel. Ich benutze Observable nur, weil es nicht weit hergeholt ist, so etwas zu tun. Offensichtlich gibt es bessere Möglichkeiten, dieses Beobachtbare zu schaffen. Ich versuche nur, einen Punkt zu demonstrieren. Normalerweise wird der Code, der das Observable abonniert hat, asynchron und möglicherweise in einem anderen Thread ausgeführt. Bei Verwendung von "foreach" kann dies zu sehr seltsamen und möglicherweise nicht deterministischen Ergebnissen führen.
Der folgende Test mit der Erweiterungsmethode "ForEach" besteht:
Folgendes schlägt mit dem Fehler fehl:
Erwartet: entspricht <0, 1, 2, 3, 4, 5, 6, 7, 8, 9>, war aber: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9>
quelle
Sie können die
FirstOrDefault()
Erweiterung verwenden, für die verfügbar istIEnumerable<T>
. Wenn Siefalse
vom Prädikat zurückkehren, wird es für jedes Element ausgeführt, es ist jedoch egal, ob es tatsächlich eine Übereinstimmung findet. Dadurch wird derToList()
Overhead vermieden.quelle
foreach(Item i in GetItems()) { i.DoStuff();}
mehr Charaktere genommen und es extrem verwirrend gemacht habenitems.All(i => { i.DoStuff(); return true; }
Ich nahm Fredriks Methode und änderte den Rückgabetyp.
Auf diese Weise unterstützt die Methode wie andere LINQ-Methoden die verzögerte Ausführung .
BEARBEITEN: Wenn dies nicht klar war, muss jede Verwendung dieser Methode mit ToList () oder einer anderen Methode enden , um die Methode zu zwingen, an der vollständigen Aufzählung zu arbeiten. Andernfalls würde die Aktion nicht ausgeführt!
Und hier ist der Test, um es zu sehen:
Wenn Sie am Ende die ToList () entfernen, schlägt der Test fehl , da der StringBuilder eine leere Zeichenfolge enthält. Dies liegt daran, dass keine Methode ForEach zur Aufzählung gezwungen hat.
quelle
ForEach
ist interessant, entspricht jedoch nicht dem Verhalten vonList.ForEach
, dessen Signatur lautetpublic void ForEach(Action<T> action)
. Es stimmt auch nicht mit dem Verhalten derObservable.ForEach
Erweiterung übereinIObservable<T>
, deren Signatur lautetpublic static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
. FWIW, dasForEach
Äquivalent zu Scala-Sammlungen, auch solche, die faul sind, haben ebenfalls einen Rückgabetyp, der für void in C # entspricht.Select
mitToList
. Der Zweck vonForEach
ist, nicht anrufen zu müssenToList
. Es sollte sofort ausgeführt werden.Halten Sie Ihre Nebenwirkungen von meiner IEnumerable fern
Wie andere hier und im Ausland darauf hingewiesen haben, LINQ und
IEnumerable
, wird erwartet, dass Methoden sind.Möchten Sie wirklich mit jedem Element in der IEnumerable "etwas tun"? Dann
foreach
ist die beste Wahl. Die Leute sind nicht überrascht, wenn hier Nebenwirkungen auftreten.Ich wette, Sie wollen keine Nebenwirkung
Nach meiner Erfahrung sind Nebenwirkungen jedoch normalerweise nicht erforderlich. Meistens wartet eine einfache LINQ-Abfrage darauf, entdeckt zu werden, zusammen mit einer Antwort von Jon Skeet, Eric Lippert oder Marc Gravell auf StackOverflow.com, in der erklärt wird, wie Sie das tun, was Sie wollen!
Einige Beispiele
Wenn Sie tatsächlich nur einen Wert aggregieren (akkumulieren), sollten Sie die
Aggregate
Erweiterungsmethode in Betracht ziehen .Vielleicht möchten Sie
IEnumerable
aus den vorhandenen Werten eine neue erstellen .Oder möchten Sie eine Nachschlagetabelle erstellen:
Die Liste (Wortspiel nicht ganz beabsichtigt) der Möglichkeiten geht weiter und weiter.
quelle
Wenn Sie wie die Aufzählung handeln wollen Rollen sollten Sie liefern jedes Element.
quelle
Es gibt eine experimentelle Version von Microsoft für interaktive Erweiterungen von LINQ (weitere Informationen zu NuGet finden Sie im Profil von RxTeams für weitere Links). Das Channel 9-Video erklärt es gut.
Die Dokumente werden nur im XML-Format bereitgestellt. Ich habe diese Dokumentation in Sandcastle ausgeführt , damit sie in einem besser lesbaren Format vorliegt. Entpacken Sie das Dokumentarchiv und suchen Sie nach index.html .
Neben vielen anderen Extras bietet es die erwartete ForEach-Implementierung. Sie können Code wie folgt schreiben:
quelle
Laut PLINQ (verfügbar seit .Net 4.0) können Sie eine
um eine parallele foreach-Schleife auf einem IEnumerable durchzuführen.
quelle
Der Zweck von ForEach ist es, Nebenwirkungen zu verursachen. IEnumerable dient zur verzögerten Aufzählung einer Menge.
Dieser konzeptionelle Unterschied ist deutlich sichtbar, wenn man ihn betrachtet.
SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));
Dies wird erst ausgeführt, wenn Sie eine "Zählung" oder eine "ToList ()" oder etwas darauf ausführen. Es ist eindeutig nicht das, was ausgedrückt wird.
Sie sollten die IEnumerable-Erweiterungen zum Einrichten von Iterationsketten verwenden und den Inhalt anhand der jeweiligen Quellen und Bedingungen definieren. Ausdrucksbäume sind leistungsstark und effizient, aber Sie sollten lernen, ihre Natur zu schätzen. Und das nicht nur, um sie zu programmieren, um ein paar Zeichen zu speichern, die die träge Bewertung überschreiben.
quelle
Viele Leute haben es erwähnt, aber ich musste es aufschreiben. Ist das nicht am klarsten / am besten lesbar?
Kurz und einfach (st).
quelle
GetItems()
Methode zurückgibt.foreach (var item in GetItems()) item.DoStuff();
das nur eine Schönheit ist.Jetzt haben wir die Möglichkeit ...
Dies eröffnet natürlich eine ganz neue Dose Fadenwürmer.
ps (Entschuldigung für die Schriftarten, das hat das System entschieden)
quelle
Wie bereits zahlreiche Antworten zeigen, können Sie eine solche Erweiterungsmethode ganz einfach selbst hinzufügen. Wenn Sie dies jedoch nicht möchten, obwohl mir in der BCL so etwas nicht bekannt ist, gibt es im
System
Namespace immer noch eine Option , wenn Sie bereits einen Verweis auf Reactive Extension haben (und wenn Sie dies nicht tun) , du solltest haben):Obwohl die Methodennamen etwas unterschiedlich sind, ist das Endergebnis genau das, wonach Sie suchen.
quelle
ForEach kann auch Chained , kurz nach der Aktion auf die pileline zurückstellen . fließend bleiben
Eine eifrige Version der Implementierung.
Edit: eine faule Version verwendet yield return, wie diese .
Die Lazy-Version MUSS materialisiert werden, zum Beispiel ToList (), sonst passiert nichts. siehe unten tolle Kommentare von ToolmakerSteve.
Ich behalte sowohl ForEach () als auch ForEachLazy () in meiner Bibliothek.
quelle
foreach(T item in enu) {action(item); yield return item;}
foreach (T item in enu) { action1(item); action2(item); action3(item); }
? Eine einzelne explizite Schleife. Ich denke, wenn es wichtig war, alle Aktionen1 auszuführen, bevor mit den Aktionen2 begonnen wird.ProcessShipping()
? Sie mailen dem Käufer, belasten seine Kreditkarte, schicken ihm aber nie seine Sachen? Auf jeden Fall nach Problemen fragen.Diese "funktionale Herangehensweise" Abstraktion leckt große Zeit. Nichts auf der Sprachebene verhindert Nebenwirkungen. Solange Sie Ihr Lambda / Delegat für jedes Element im Container aufrufen können, erhalten Sie das Verhalten "ForEach".
Hier zum Beispiel eine Möglichkeit, srcDictionary mit destDictionary zusammenzuführen (falls der Schlüssel bereits vorhanden ist - überschreibt)
Dies ist ein Hack und sollte in keinem Produktionscode verwendet werden.
quelle
foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }
? Wenn nicht im Produktionscode, wo und warum sollten Sie dies jemals verwenden?Inspiriert von Jon Skeet habe ich seine Lösung um Folgendes erweitert:
Verlängerungsmethode:
Klient:
. . .
quelle
MoreLinq hat
IEnumerable<T>.ForEach
und eine Menge anderer nützlicher Erweiterungen. Es lohnt sich wahrscheinlich nicht, die Abhängigkeit nur für zu nehmenForEach
, aber es gibt eine Menge nützlicher Dinge.https://www.nuget.org/packages/morelinq/
https://github.com/morelinq/MoreLINQ
quelle
Ich bin mit der Vorstellung nicht einverstanden, dass Linkerweiterungsmethoden nebenwirkungsfrei sein sollten (nicht nur, weil dies nicht der Fall ist, sondern jeder Delegierte Nebenwirkungen erzielen kann).
Folgendes berücksichtigen:
Was das Beispiel zeigt, ist eigentlich nur eine Art Spätbindung, mit der man eine von vielen möglichen Aktionen aufrufen kann, die Nebenwirkungen auf eine Folge von Elementen haben, ohne ein großes Schalterkonstrukt schreiben zu müssen, um den Wert zu dekodieren, der die Aktion definiert und übersetzt es in seine entsprechende Methode.
quelle
Um fließend zu bleiben, kann man einen solchen Trick anwenden:
quelle
Für VB.NET sollten Sie Folgendes verwenden:
quelle
List
oder habenIList
.IEnumerable
Schreiben Sie im Allgemeinen das VB-Äquivalent der ForEach-Erweiterungsmethode der akzeptierten Antwort .Noch ein
ForEach
Beispielquelle