8

我需要一个采用Action(或Func)的方法,但Action 有混合数量的参数。实现这些重载的最直接和紧凑的方法是什么:

public void Execute<T>(Action<T> action, T param) {
    // TODO: Implement something like:
    // Execute(action, param, null);
}

public void Execute<T1,T2>(Action<T1,T2> action, T1 param1, T2 param2) {
    // TODO: Implement something like:
    // Execute(action, param1, param2, null);
}

public void Execute<T1,T2,T3>(Action<T1,T2,T3> action, T1 param1, T2 param2, T3 param3) {
    DoStuff();
    action(param1, param2, param3)
    DoMoreStuff();
}

// OR any other type of higher order function-solution
public void Execute(Action action, params object[] parameters) { ... } // ???

方法的内容是完全一样的,除了动作的执行和它的参数。

如果可能,不要使用任何 C# 4.0 特定的功能来解决这个问题。

4

2 回答 2

8

方法的内容是完全一样的,除了动作的执行和它的参数。

使用更高阶函数的尖叫声,但是由于您已经参数化了所有正在更改的位(操作及其参数的执行),您已经在那里了。抱歉,看来您必须手动实现这些重载。

由于传递的委托不匹配,因此仅使用空值进行链接是行不通的。您可以做的是将传递的动作/函数包装在 lambda 中以剥离其他参数

public void Execute(Action<T> action, T param) {
     Execute( (a, _) => action(a) , param, null);
}

public void Execute(Action<T1, T2> action, T1 param1, T2 param2) {
    Execute( (a, b, _) => action(a, b) , param1, param2,  null);
}

public void Execute(Action<T1, T2, T3> action, T1 param1, T2 param2, T3 param3) {
    DoStuff();
    action(param1, param2, param3)
    DoMoreStuff();
}
于 2010-08-18T07:54:03.117 回答
5

这实际上是最好的方法(记住 Johannes 的观点,你也可以使用更高阶的函数),因为它是最友好的(代表将自动与正确数量和类型的参数匹配)并且确实不需要任何麻烦DynamicInvoke的电话。

但是,您的最后一个方法定义是有问题的。就其Action本质而言,它不接受任何参数,因此它不会很好地处理params object[]参数。如果你想要一个接受可变数量参数的最终重载,我DynamicInvoke毕竟会选择这个方法调用:

public void Execute(Delegate action, params object[] parameters)
{
    DoStuff();
    action.DynamicInvoke(parameters);
    DoMoreStuff();
}

但要扩展约翰内斯所说的话,我认为他基本上是这样说的:

public Action<T1, T2, T3> CreateAction<T1, T2, T3>(Action action)
{
    return (T1 x, T2 y, T3 z) => action();
}

public Action<T1, T2, T3> CreateAction<T1, T2, T3>(Action<T1> action, T1 arg)
{
    return (T1 x, T2 y, T3 z) => action(arg);
}

等等——换句话说,你已经做了什么,但在一般情况下,代码可以在其他地方重用。

于 2010-08-18T09:52:50.400 回答