Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# syntax for applying an action to a varying number of objects [duplicate]

Tags:

c#

What I want to do is combine lambda syntax with "params" to carry out an action on a series of object.

Let's say I want to make a bunch of controls invisible.

After a bit of fiddling I ended up with an extension method:

public static void On<T>(this Action<T> actionToCarryOut,params T[] listOfThings)
{
    foreach (var thing in listOfThings)
    {
        actionToCarryOut(thing);
    }
}

and then I can create an action:

Action<Control> makeInvisible = c => c.Visible = false;

and then call it:

makeInvisible.On(control1,control2, control3,control4);

This isn't very nice syntax though - it feels horribly clumsy.

I can create a method "Apply" in my base class:

protected void Apply<T>(Action<T> action, params T[] appliedTo)
{
    foreach (var item in appliedTo)
    {
        action(item);
    }
}

and then call it like this:

Apply<Control>(
    c => c.Visible = false,
    control1,
    control2,
    control3,);

But that means repeating the method in every base class I need it in, and I lose the advantage of type inference.

Is there a less clumsy way of doing this?

Edit: The nicest method I've seen so far is the fluent approach, which (with a couple of tweaks) would allow me to write:

Apply.Method((Control c) => c.Visible = false).To(
    control1, 
    control2, 
    control3, 
    control4};

This is 91 characters, compared to 107 for using a simple "foreach". Which leads me to believe that "foreach" might actually be the best approach after all!

like image 203
Andrew Ducker Avatar asked Jul 16 '13 13:07

Andrew Ducker


2 Answers

You could use an extension method like this instead:

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

And then call it like:

new Control[] { control1, control2, control3 }.ForEach(makeInvisible);

Or simply

new Control[] { control1, control2, control3 }.ForEach(x => x.Visible = false);

If control1..n are all of the same type you can omit the base class:

new[] { control1, control2, control3 }.ForEach(x => x.Visible = false);
like image 169
p.s.w.g Avatar answered Oct 26 '22 10:10

p.s.w.g


Why not just call it as a regular static method instead of an extension?

public static class Apply
{
    public static void To<T>(this Action<T> actionToCarryOut,params T[] listOfThings)
    {
        foreach (var thing in listOfThings)
        {
            actionToCarryOut(thing);
        }
    }
}

Then call it like this:

Apply.To<Control>(c => c.Visible = false,control1,control2, control3,control4);

EDIT

Here's a version that uses a Fluent syntax:

public class Apply<T>
{
    private Action<T> _action;

    public Apply(Action<T> action) { _action = action; }

    public static Apply<T> Method(Action<T> actionToCarryOut)
    {
        return new Apply<T>(actionToCarryOut);
    }

    public void To(params T[] listOfThings)
    {
        foreach (var thing in listOfThings)
        {
            _action(thing);
        }
    }

}

Usage:

Apply<Control>.Method(c => c.Visible = false).To(control1,control2, control3,control4);
like image 40
D Stanley Avatar answered Oct 26 '22 10:10

D Stanley