Is there an elegant way to repeat an action?

后端 未结 9 1243
野的像风
野的像风 2020-12-16 08:56

In C#, using .NET Framework 4, is there an elegant way to repeat the same action a determined number of times? For example, instead of:

int repeat = 10;
for          


        
相关标签:
9条回答
  • 2020-12-16 09:35
    Enumerable.Repeat<Action>(() => { Console.WriteLine("Hello World"); this.DoSomething(); },10).ToList().ForEach(f => f.Invoke());
    

    elegant isn't it?

    0 讨论(0)
  • 2020-12-16 09:38

    I wrote it as an Int32 extension method. At first I thought maybe that doesn't sound like a good idea, but it actually seems really great when you use it.

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

    Usage:

    5.Repeat(DoThing);
    
    value.Repeat(() => queue.Enqueue(someItem));
    
    (value1 - value2).Repeat(() => {
       // complex implementation
    });
    

    Note that it will do nothing for values <= 0. At first I was going to throw for negatives, but then I'd always have to check which number is greater when comparing two. This allows a difference to work if positive and do nothing otherwise.

    You could write an Abs extension method (either value.Abs().Repeat(() => { }); or -5.RepeatAbs(() => { });) if you wanted to repeat regardless of sign and then the order of the difference of two numbers wouldn't matter.

    Other variants are possible as well, like passing the index, or projecting into values similar to Select.

    I know there is Enumerable.Range but this is a lot more concise.

    0 讨论(0)
  • 2020-12-16 09:42

    For brevity of a one liner you could do this. Not sure what you think...

    Enumerable.Repeat<Action>(() => 
    {
        Console.WriteLine("Hello World.");
        this.DoSomeStuff();
    }, 10).ToList().ForEach(x => x());
    
    0 讨论(0)
  • 2020-12-16 09:42

    Without rolling out your own extension, I guess you can do something like this

        Action toRepeat = () => {
            Console.WriteLine("Hello World.");
             this.DoSomeStuff();
        };
    
        int repeat = 10;
        Enumerable.Range(0, repeat).ToList().ForEach(i => toRepeat());
    
    0 讨论(0)
  • 2020-12-16 09:49
    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());
    

    these options are not elegant because of ToList(), but both worked in my case

    0 讨论(0)
  • 2020-12-16 09:54

    There is no built-in way to do this.

    The reason is that C# as it is tries to enforce a divide between the functional and imperative sides of the language. C# only makes it easy to do functional programming when it is not going to produce side effects. Thus you get collection-manipulation methods like LINQ's Where, Select, etc., but you do not get ForEach.1

    In a similar way, what you are trying to do here is find some functional way of expressing what is essentially an imperative action. Although C# gives you the tools to do this, it does not try to make it easy for you, as doing so makes your code unclear and non-idiomatic.

    1 There is a List<T>.ForEach, but not an IEnumerable<T>.ForEach. I would say the existence of List<T>.ForEach is a historical artifact stemming from the framework designers not having thought through these issues around the time of .NET 2.0; the need for a clear division only became apparent in 3.0.

    0 讨论(0)
提交回复
热议问题