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?

231voto

Coincoin Punkte 26516

Es gibt bereits eine foreach die in der Sprache enthalten ist, die in den meisten Fällen die Aufgabe erfüllt.

Ich würde es hassen, das Folgende zu sehen:

list.ForEach( item =>
{
    item.DoSomething();
} );

Anstelle von:

foreach(Item item in list)
{
     item.DoSomething();
}

Letztere ist klarer und leichter zu lesen in den meisten Situationen obwohl es vielleicht ein bisschen länger dauert, sie zu tippen.

Ich muss jedoch zugeben, dass ich meine Haltung in dieser Frage geändert habe; eine ForEach() Erweiterungsmethode wäre in einigen Situationen tatsächlich nützlich.

Hier sind die wichtigsten Unterschiede zwischen der Erklärung und der Methode:

  • Typüberprüfung: foreach wird zur Laufzeit ausgeführt, ForEach() ist zur Kompilierzeit (Großes Plus!)
  • Die Syntax für den Aufruf eines Delegaten ist in der Tat viel einfacher: objects.ForEach(DoSomething);
  • ForEach() könnte verkettet werden: obgleich die Schlechtigkeit/Nützlichkeit einer solchen Funktion zur Diskussion steht.

Das sind alles großartige Argumente, die hier von vielen gemacht wurden, und ich kann verstehen, warum die Leute die Funktion vermissen. Ich hätte nichts dagegen, wenn Microsoft bei der nächsten Iteration des Frameworks eine Standard-ForEach-Methode hinzufügen würde.

89voto

aku Punkte 118808

Die ForEach-Methode wurde vor LINQ hinzugefügt. Wenn Sie die ForEach-Erweiterung hinzufügen, wird sie aufgrund der Einschränkungen der Erweiterungsmethoden niemals für Listeninstanzen aufgerufen. Ich denke, der Grund, warum es nicht hinzugefügt wurde, ist, um nicht mit bestehenden stören.

Wenn Sie diese kleine nette Funktion jedoch wirklich vermissen, können Sie Ihre eigene Version entwickeln

public static void ForEach<T>(
    this IEnumerable<T> source,
    Action<T> action)
{
    foreach (T element in source) 
        action(element);
}

60voto

Jay Bazuzi Punkte 43111

Sie könnten diese Erweiterungsmethode schreiben:

// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
    foreach (var e in source)
    {
        action(e);
        yield return e;
    }
}

Profis

Erlaubt die Verkettung:

MySequence
    .Apply(...)
    .Apply(...)
    .Apply(...);

Nachteile

Es wird nicht wirklich etwas tun, bis Sie etwas tun, um die Iteration zu erzwingen. Aus diesem Grund sollte es nicht aufgerufen werden .ForEach() . Sie könnten schreiben .ToList() am Ende, oder Sie könnten auch diese Erweiterungsmethode schreiben:

// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
    foreach (var e in source)
    {
        // do nothing
        ;
    }

    return source;
}

Dies kann eine zu große Abweichung von den mitgelieferten C#-Bibliotheken sein; Leser, die mit Ihren Erweiterungsmethoden nicht vertraut sind, werden nicht wissen, was sie von Ihrem Code halten sollen.

46voto

mancaus Punkte 2923

Die Diskussion hier gibt die Antwort:

In der konkreten Diskussion, die ich miterlebt habe, ging es tatsächlich um funktionale Reinheit. In einem Ausdruck wird häufig davon ausgegangen, dass es keine Seiteneffekte gibt. Die Verwendung von ForEach lädt geradezu zu Seiteneffekten ein, anstatt sie einfach in Kauf zu nehmen. -- Keith Farmer (Partner)

Grundsätzlich wurde die Entscheidung getroffen, die Erweiterungsmethoden funktional "rein" zu halten. Ein ForEach würde bei der Verwendung der Enumerable-Erweiterungsmethoden zu Seiteneffekten führen, was nicht die Absicht war.

20voto

Chris Zwiryk Punkte 1321

Ich stimme zwar zu, dass es besser ist, die integrierte foreach Konstrukts in den meisten Fällen finde ich die Verwendung dieser Variante der ForEach<>-Erweiterung etwas angenehmer als die Verwaltung des Index in einer regulären foreach mich selbst:

public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
    if (action == null) throw new ArgumentNullException("action");

    var index = 0;

    foreach (var elem in list)
        action(index++, elem);

    return index;
}

Beispiel

var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));

würde Sie geben:

Person #0 is Moe
Person #1 is Curly
Person #2 is Larry

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