Frage

Ich habe eine Enumerable<T> und bin auf der Suche nach einer Methode, die ich eine Aktion für jedes Element ausführen kann, die Art wie Select aber dann für Nebenwirkungen. So etwas wie:

string[] Names = ...;
Names.each(s => Console.Writeline(s));

oder

Names.each(s => GenHTMLOutput(s));   
// (where GenHTMLOutput cannot for some reason receive the enumerable itself as a parameter)

habe ich Select(s=> { Console.WriteLine(s); return s; }) versuchen, aber es war nichts zu drucken.

War es hilfreich?

Lösung

Eine schnelle und einfache Möglichkeit, dies zu erhalten, ist:

Names.ToList().ForEach(e => ...);

Andere Tipps

Sie suchen für die immer schwer FürJeden, die derzeit nur auf der Liste generischen Sammlung vorhanden ist. Es gibt viele Diskussionen darüber, ob Online-Microsoft soll oder diese als LINQ Methode nicht hinzufügen sollte. Derzeit müssen Sie Ihre eigene Rolle:

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

Während die All() ähnliche Methode Fähigkeiten bietet, ist es Use-Case ist für jedes Objekt ein Prädikat Test für die Durchführung statt einer Aktion. Natürlich kann es andere Aufgaben auszuführen überzeugt werden, aber dies ändert sich etwas, die Semantik und würde es für die anderen Code schwieriger zu interpretieren (das heißt ist diese Verwendung von All() für ein Prädikat Test oder eine Aktion?).

Disclaimer: Dieser Beitrag nicht mehr meine ursprüngliche Antwort ähnelt, sondern beinhaltet die etwa sieben Jahre Erfahrung, die ich seit gewonnen habe. Ich habe die bearbeiten, weil es sich um eine hoch angesehene Frage und keine der vorhandenen Antworten wirklich alle Winkel abgedeckt. Wenn Sie meine ursprüngliche Antwort sehen wollen, dann ist es für diesen Beitrag in der Revisionshistorie zur Verfügung.


Das erste, was zu verstehen, hier ist C # Linq Operationen wie Select(), All(), Where(), etc, haben ihre Wurzeln in Er empfiehlt eine traditionelle foreach Schleife:

  

[foreach ()] fügt Null neue repräsentative Macht der Sprache. Dadurch lässt Sie diese vollkommen klar Code neu schreiben:

     

foreach(Foo foo in foos){ statement involving foo; }

     

in diesem Code:

     

foos.ForEach(foo=>{ statement involving foo; });

Sein Punkt ist, wenn Sie genau auf Ihrer Syntax Optionen aussehen, Sie gewinnen nichts Neues aus einer ForEach() Erweiterung im Vergleich zu einer traditionellen foreach Schleife. Ich bin nicht einverstanden teilweise. Stellen Sie sich vor Sie haben dies:

 foreach(var item in Some.Long(and => possibly)
                         .Complicated(set => ofLINQ)
                         .Expression(to => evaluate)
 {
     // now do something
 } 

Dieser Code verschleiert Bedeutung, weil es das foreach Schlüsselwort aus den Vorgängen in der Schleife trennt. Es listet auch die Schleife Befehl vor zu den Operationen, die die Reihenfolge definieren, auf die die Schleife arbeitet. Es fühlt sich viel natürlicher diese Operationen an erster Stelle stehen haben zu wollen, und dann haben die die Schleife Befehl an dem Ende der Abfrage-Definition. Außerdem ist der Code nur hässlich. Es scheint, als wäre es viel schöner, in der Lage sein, dies zu schreiben:

Some.Long(and => possibly)
   .Complicated(set => ofLINQ)
   .Expression(to => evaluate)
   .ForEach(item => 
{
    // now do something
});

Aber auch hier kam ich schließlich um zu Eric Sicht. Ich erkannte Code wie Sie oben sehen, ist für eine zusätzliche Variable rufen. Wenn Sie einen komplizierten Satz von LINQ Ausdrücke wie die haben, können Sie wertvolle Informationen, um Ihren Code hinzufügen, indem Sie zuerst das Ergebnisses des LINQ Ausdrucks ein neue Variablen zuweisen:

var queryForSomeThing = Some.Long(and => possibly)
                        .Complicated(set => ofLINQ)
                        .Expressions(to => evaluate);
foreach(var item in queryForSomeThing)
{
    // now do something
}

Dieser Code fühlt sich natürlicher. Es setzt das foreach Schlüsselwort zurück neben dem Rest der Schleife, und nach der Abfragedefinition. Vor allem kann der Variablenname neue Informationen hinzuzufügen, die Zukunft Programmierer hilfreich sein wird versucht, den Zweck der LINQ-Abfrage zu verstehen. Auch hier sehen wir die gewünschte ForEach() Operator wirklich keine neuen Ausdruckskraft der Sprache hinzugefügt.

Allerdings fehlen wir noch zwei Merkmale einer hypothetischen ForEach() Erweiterungsmethode:

  1. Es ist nicht zusammensetzbare. Ich kann keine weiteren .Where() oder GroupBy() oder OrderBy() nach einem foreach Schleife inline mit dem Rest des Codes hinzufügen, ohne eine neue Anweisung zu schaffen.
  2. Es ist nicht faul. Diese Vorgänge passieren sofort. Es ist nicht alniedrige me auf, sagen wir, haben eine Form, wo ein Benutzer eine Operation als ein Feld in einem größeren Bildschirm wählt, die nicht beaufschlagt wird, bis der Benutzer einen Befehl-Taste drückt. Diese Form kann dem Benutzer erlauben, ihre Meinung zu ändern, bevor der Befehl ausgeführt wird. Das ist völlig normal ( leicht auch) mit einer LINQ-Abfrage, aber nicht so einfach, mit einem foreach.

Sie könnten sich natürlich Ihre eigene ForEach() Erweiterungsmethode machen. Mehrere andere Antworten haben Implementierungen dieser Methode bereits; es ist gar nicht so kompliziert. Allerdings habe ich das Gefühl, es nicht notwendig ist. Es gibt bereits eine bestehende Methode, die paßt, was wir sowohl von semantischen und operativen Gesichtspunkten tun wollen. Beide der fehlenden Features oben kann durch Nutzung des bestehenden Select() Betreiber zu richten.

Select() paßt die Art der Transformation oder Projektion oberhalb von beiden Beispielen beschrieben. Denken Sie aber daran, dass ich immer noch Nebenwirkungen haben würde vermeiden. Der Aufruf von Select() sollte entweder neue Objekte oder Projektionen von den Originalen zurück. Dies kann manchmal durch die Verwendung eines anonymen Typs oder dynamischen Objekt unterstützt werden (wenn und nur wenn nötig). Wenn Sie die Ergebnisse müssen bestehen bleiben, sagen, eine ursprüngliche Liste Variable, können Sie immer .ToList() anrufen und es zurück zu Ihrem ursprünglichen Variablen zuweisen. Ich werde hier hinzufügen, dass ich lieber arbeiten mit IEnumerable<T> Variablen so viel wie möglich über konkretere Typen.

myList = myList.Select(item => new SomeType(item.value1, item.value2 *4)).ToList();

Zusammenfassung:

  1. Just-Stick mit foreach die meiste Zeit.
  2. Wenn foreach wirklich nicht tun (was wahrscheinlich nicht so oft, wie Sie denken), verwenden Select()
  3. Wenn Sie Select() verwenden müssen, können Sie nach wie vor generell vermeiden (programm sichtbar) Nebenwirkungen, die möglicherweise von einem anonymen Typ zu projizieren.

Leider gibt es keine integrierte Möglichkeit, dies in der aktuellen Version von LINQ zu tun. Das Framework Team vernachlässigt, um eine .ForEach Erweiterung Methode hinzufügen. Es gibt eine gute Diskussion darüber im Gange, jetzt auf den folgenden Blog.

http://blogs.msdn.com/kirillosenkov/ Archiv / 2009/01/31 / foreach.aspx

Es ist ziemlich einfach, wenn man hinzuzufügen.

public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) {
  foreach ( var cur in enumerable ) {
    action(cur);
  }
}

Sie können dies nicht sofort mit LINQ und IEnumerable - Sie müssen entweder eigene Erweiterungsmethode implementieren, oder werfen Sie Ihre Aufzählung auf ein Array mit LINQ und rufen Sie dann Array.ForEach ():

Array.ForEach(MyCollection.ToArray(), x => x.YourMethod());

Bitte beachten Sie, dass aufgrund der Art und Weise Werttypen und Strukturen arbeiten, wenn die Sammlung eines Werttyps ist und Sie die Elemente der Kollektion auf diese Weise ändern, wird es keine Auswirkungen auf die Elemente der ursprünglichen Sammlung haben.

Da LINQ ist so konzipiert, eine Abfrage-Funktion sein und nicht eine Update-Funktion werden Sie keine Erweiterung finden, die Methoden auf IEnumerable ausführt , denn das würde ermöglicht es Ihnen, ein Verfahren auszuführen (möglicherweise mit Nebenwirkungen). In diesem Fall können Sie auch nur Stick mit

  

foreach (string name in Names)
  Console.WriteLine (name);

Nun, können Sie auch den Standard foreach Schlüsselwort verwenden, ist es nur Format in einen oneliner:

foreach(var n in Names.Where(blahblah)) DoStuff(n);

Sorry, dachte diese Option verdient, hier zu sein:)

Es gibt eine ForEach-Methode aus der Liste. Sie könnten die Enumerable konvertieren durch den Aufruf der .ToList () -Methode zur Liste, und dann von der die ForEach-Methode aufrufen.

Als Alternative habe ich von Leuten gehört, ihre eigene ForEach-Methode aus der IEnumerable definieren. Dies kann im Wesentlichen erreicht werden, indem die ForEach-Methode aufgerufen wird, sondern es in einer Erweiterungsmethode Verpackung:

public static class IEnumerableExtensions
{
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> _this, Action<T> del)
    {
        List<T> list = _this.ToList();
        list.ForEach(del);
        return list;
    }
}

Mit Parallel Linq:

Names.AsParallel (). ForAll (name => ...)

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