480 Stimmen

Warum gibt es keine ForEach-Erweiterungsmethode für IEnumerable?

Angeregt durch eine andere Frage nach dem fehlenden Zip Funktion:

Warum gibt es keine ForEach Erweiterungsmethode auf der IEnumerable Schnittstelle? Oder irgendwo? Die einzige Klasse, die eine ForEach Methode ist List<> . Gibt es einen Grund, warum sie fehlt, vielleicht die Leistung?

16voto

Aaron Powell Punkte 24630

Das habe ich mich auch immer gefragt, deshalb habe ich das immer bei mir:

public static void ForEach<T>(this IEnumerable<T> col, Action<T> action)
{
    if (action == null)
    {
        throw new ArgumentNullException("action");
    }
    foreach (var item in col)
    {
        action(item);
    }
}

Nette kleine Erweiterungsmethode.

15voto

Jay Bazuzi Punkte 43111

Eine Abhilfemaßnahme besteht darin, Folgendes zu schreiben .ToList().ForEach(x => ...) .

Profis

Einfach zu verstehen - der Leser muss nur wissen, was mit C# ausgeliefert wird, keine zusätzlichen Erweiterungsmethoden.

Syntaktisches Rauschen ist sehr gering (fügt nur ein wenig überflüssigen Code hinzu).

Das kostet normalerweise keinen zusätzlichen Speicherplatz, da ein nativer .ForEach() müsste ohnehin die gesamte Sammlung realisieren.

Nachteile

Die Reihenfolge der Operationen ist nicht ideal. Ich würde lieber ein Element erkennen, dann darauf reagieren und dann wiederholen. In diesem Code werden zuerst alle Elemente erkannt und dann nacheinander bearbeitet.

Wenn die Realisierung der Liste eine Ausnahme auslöst, können Sie nie auf ein einziges Element einwirken.

Wenn die Aufzählung unendlich ist (wie die natürlichen Zahlen), haben Sie Pech gehabt.

7voto

Scott Dorman Punkte 41206

Es gab also viele Kommentare darüber, dass eine ForEach-Erweiterungsmethode nicht geeignet ist, weil sie keinen Wert zurückgibt wie die LINQ-Erweiterungsmethoden. Dies ist zwar eine sachliche Aussage, aber sie ist nicht ganz zutreffend.

Die LINQ-Erweiterungsmethoden geben alle einen Wert zurück, sodass sie miteinander verkettet werden können:

collection.Where(i => i.Name = "hello").Select(i => i.FullName);

Nur weil LINQ mit Erweiterungsmethoden implementiert ist, bedeutet das jedoch nicht, dass Erweiterungsmethoden なければならない auf die gleiche Weise verwendet werden und einen Wert zurückgeben. Eine Erweiterungsmethode zu schreiben, um eine allgemeine Funktionalität darzustellen, die keinen Wert zurückgibt, ist eine durchaus zulässige Verwendung.

Das spezielle Argument für ForEach ist, dass aufgrund der Einschränkungen für Erweiterungsmethoden (nämlich, dass eine Erweiterungsmethode niemals eine geerbte Methode mit der Option gleiche Signatur ), kann es eine Situation geben, in der die benutzerdefinierte Erweiterungsmethode in allen Klassen verfügbar ist, die IEnumerable impelementieren <T > außer Liste <T >. Dies kann zu Verwirrung führen, wenn sich die Methoden unterschiedlich verhalten, je nachdem, ob die Erweiterungsmethode oder die Vererbungsmethode aufgerufen wird oder nicht.

6voto

Martijn Punkte 11548

Sie könnten die (verkettbare, aber faul ausgewertete) Select zuerst Ihre Operation durchführen und dann die Identität zurückgeben (oder etwas anderes, wenn Sie es vorziehen)

IEnumerable<string> people = new List<string>(){"alica", "bob", "john", "pete"};
people.Select(p => { Console.WriteLine(p); return p; });

Sie müssen sicherstellen, dass sie noch bewertet wird, entweder mit Count() (die billigste Operation zum Aufzählen afaik) oder eine andere Operation, die Sie sowieso benötigten.

Ich würde es allerdings begrüßen, wenn es in die Standardbibliothek aufgenommen würde:

static IEnumerable<T> WithLazySideEffect(this IEnumerable<T> src, Action<T> action) {
  return src.Select(i => { action(i); return i; } );
}

Der obige Code wird dann zu people.WithLazySideEffect(p => Console.WriteLine(p)) was im Grunde dem foreach entspricht, aber träge und verkettbar ist.

5voto

Dave Clausen Punkte 1247

Beachten Sie, dass die MehrLINQ NuGet bietet die ForEach Erweiterungsmethode, nach der Sie suchen (sowie eine Pipe Methode, die den Delegaten ausführt und sein Ergebnis liefert). Siehe:

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X