it-swarm.com.de

Gibt es eine elegante Möglichkeit, eine Aktion zu wiederholen?

Gibt es in C # mit .NET Framework 4 eine elegante Möglichkeit, dieselbe Aktion eine bestimmte Anzahl von Malen zu wiederholen? Zum Beispiel anstelle von:

int repeat = 10;
for (int i = 0; i < repeat; i++)
{
    Console.WriteLine("Hello World.");
    this.DoSomeStuff();
}

Ich möchte etwas schreiben wie:

Action toRepeat = () =>
{
    Console.WriteLine("Hello World.");
    this.DoSomeStuff();
};

toRepeat.Repeat(10);

oder:

Enumerable.Repeat(10, () =>
{
    Console.WriteLine("Hello World.");
    this.DoSomeStuff();
});

Ich weiß, dass ich für das erste Beispiel eine eigene Erweiterungsmethode erstellen kann, aber gibt es nicht eine vorhandene Funktion, durch die dies bereits möglich ist?

34

Es gibt keine integrierte Möglichkeit, dies zu tun.

Der Grund ist, dass C # versucht, eine Trennung zwischen den funktionalen und den imperativen Seiten der Sprache zu erzwingen. C # macht die funktionale Programmierung nur dann einfach, wenn keine Nebenwirkungen auftreten. So erhalten Sie Methoden zum Sammeln von Manipulationen wie LINQs Where, Select usw., aber Sie erhalten nicht ForEach .1

In ähnlicher Weise versuchen Sie hier, eine funktionale Möglichkeit zu finden, um das auszudrücken, was im Wesentlichen eine zwingende Aktion ist. Obwohl C # Ihnen die Werkzeuge dafür bietet, versucht es nicht, es Ihnen leicht zu machen, da dies Ihren Code unklar und nicht idiomatisch macht.

1 Es gibt einen List<T>.ForEach, aber keinen IEnumerable<T>.ForEach. Ich würde sagen, dass List<T>.ForEach ein historisches Artefakt ist, das von den Framework-Designern stammt, die sich nicht um .NET 2.0 herumgedacht haben. Die Notwendigkeit einer klaren Trennung wurde erst in 3.0 deutlich.

23
Domenic

So was?

using System.Linq;

Enumerable.Range(0, 10).ForEach(arg => toRepeat());

Dadurch wird Ihre Methode 10 Mal ausgeführt.

[Bearbeiten]

Ich bin es gewohnt, ForEach Erweiterungsmethode auf Enumerable zu haben, dass ich vergessen habe, dass es nicht Teil von FCL ist.

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

Ohne die Erweiterungsmethode ForEach können Sie Folgendes tun:

Enumerable.Range(0, 10).ToList().ForEach(arg => toRepeat());

[Bearbeiten]

Ich denke, die eleganteste Lösung ist die Implementierung einer wiederverwendbaren Methode:

public static void RepeatAction(int repeatCount, Action action)
{
    for (int i = 0; i < repeatCount; i++)
        action();
}

Verwendungszweck:

RepeatAction(10, () => { Console.WriteLine("Hello World."); });
37
Alex Aza

Um es kurz zu machen, können Sie dies tun. Nicht sicher, was du denkst ...

Enumerable.Repeat<Action>(() => 
{
    Console.WriteLine("Hello World.");
    this.DoSomeStuff();
}, 10).ToList().ForEach(x => x());
8
Aron

Ich denke, dass Sie, ohne Ihre eigene Erweiterung auszurollen, so etwas tun können

    Action toRepeat = () => {
        Console.WriteLine("Hello World.");
         this.DoSomeStuff();
    };

    int repeat = 10;
    Enumerable.Range(0, repeat).ToList().ForEach(i => toRepeat());
7
Bala R
Enumerable.Repeat<Action>(() => { Console.WriteLine("Hello World"); this.DoSomething(); },10).ToList().ForEach(f => f.Invoke());

elegant ist es nicht?

4
Ali Humayun

Deklaration einer Erweiterung:

public static void Repeat(this Action action, int times){
    while (times-- > 0)
        action.Invoke();
}

Sie können die Erweiterungsmethode folgendermaßen verwenden:

        new Action(() =>
                   {
                       Console.WriteLine("Hello World.");
                       this.DoSomeStuff();
                   }).Repeat(10);
1
Toni Rossmann
Table table = frame.AddTable();
int columnsCount = 7;

Enumerable.Repeat<Func<Column>>(table.AddColumn, columnsCount)
          .ToList()
          .ForEach(addColumn => addColumn());
//or
Enumerable.Range(0, columnsCount)
          .ToList()
          .ForEach(iteration => table.AddColumn());

diese Optionen sind wegen ToList () nicht elegant, aber beide haben in meinem Fall funktioniert

1
Oleg

Ich habe es als eine Int32-Erweiterungsmethode geschrieben. Zuerst dachte ich, das klingt vielleicht nicht nach einer guten Idee, aber es scheint wirklich großartig zu sein, wenn Sie es verwenden.

public static void Repeat(
   this int count,
   Action action
) {
   for (int x = 0; x < count; x += 1)
      action();
}

Verwendungszweck:

5.Repeat(DoThing);

value.Repeat(() => queue.Enqueue(someItem));

(value1 - value2).Repeat(() => {
   // complex implementation
});

Beachten Sie, dass es nichts für Werte <= 0 tut. Zuerst wollte ich Negative werfen, aber dann musste ich immer überprüfen, welche Zahl größer ist, wenn man zwei vergleicht. Dies ermöglicht, dass ein Unterschied funktioniert, wenn er positiv ist und nichts anderes tut.

Sie könnten eine Abs-Erweiterungsmethode schreiben (entweder value.Abs().Repeat(() => { }); oder -5.RepeatAbs(() => { });), wenn Sie unabhängig vom Vorzeichen wiederholen möchten, und dann spielt die Reihenfolge der Differenz zweier Zahlen keine Rolle.

Andere Varianten sind ebenfalls möglich, wie das Übergeben des Index oder das Projizieren in Werte ähnlich wie Select.

Ich weiß, dass es Enumerable.Range gibt, aber das ist viel prägnanter.

0
Dave Cousineau