13

我想要做的是将 lambda 语法与“参数”结合起来对一系列对象执行操作。

假设我想让一堆控件不可见。

经过一番摆弄,我最终得到了一个扩展方法:

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

然后我可以创建一个动作:

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

然后调用它:

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

虽然这不是很好的语法 - 感觉非常笨拙。

我可以在我的基类中创建一个“应用”方法:

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

然后这样称呼它:

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

但这意味着在我需要它的每个基类中重复该方法,并且我失去了类型推断的优势。

有没有更笨拙的方法来做到这一点?

编辑:到目前为止我见过的最好的方法是流利的方法,它(有一些调整)可以让我写:

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

这是 91 个字符,而使用简单的“foreach”则为 107 个字符。这让我相信“foreach”实际上可能是最好的方法!

4

4 回答 4

7

您可以改用这样的扩展方法:

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

然后这样称呼它:

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

或者干脆

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

如果control1..n都是同一类型,则可以省略基类:

new[] { control1, control2, control3 }.ForEach(x => x.Visible = false);
于 2013-07-16T13:06:30.310 回答
4

也许您想通过构建一组对象然后在该集合上调用一个方法来采取更多的 OO 方法:

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

ForEach 扩展函数在LinqKit 工具集中定义。

于 2013-07-16T13:06:50.727 回答
4

为什么不将其称为常规静态方法而不是扩展?

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

然后像这样调用它:

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

编辑

这是一个使用 Fluent 语法的版本:

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);
        }
    }

}

用法:

Apply<Control>.Method(c => c.Visible = false).To(control1,control2, control3,control4);
于 2013-07-16T13:07:21.180 回答
2

或者,你可以这样做,

control1.Visible = false;
control2.Visible = false;
control3.Visible = false;
control4.Visible = false;

这是更少的代码行,运行速度更快。但是,如果您想要扩展一个比您的示例中的案例不那么琐碎的案例,怎么样。

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

然后你可以,稍微修改你的原件

public static void Act<T>(Action<T> action, params T[] targets)
{
    targets.ForEach(action);
}

允许,

Act(ctl => ctl.Visible = false, control1, control2, control3, control4); 

但是,我建议

var controls = new[] { control1, control2, control3, control4 };

foreach (var control in controls)
{
    control.Visible = false;
}

比任何扩展方法都更具可读性,或者如果你把它放在一行上它非常熟悉。

foreach (var control in new[] { control1, control2, control3, control4 })
    control.Visible = false;

我认为这些最终示例说明了为什么框架中省略了这个看似有用的扩展。

于 2013-07-16T13:12:57.303 回答