C# Action 和 Func 参数重载

发布于 2024-09-15 00:19:49 字数 806 浏览 7 评论 0原文

我需要一个采用 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 特定的功能来解决此问题。

I need a method that takes an Action (or a Func), but the Action has a mixed number of parameters. What is the most straight forward and compact way to implement these overloads:

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) { ... } // ???

The content of the methods are exactly the same, except for the execution of the action and its parameters.

If possible, don't use any C# 4.0-specific features to solve this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自此以后,行同陌路 2024-09-22 00:19:49

方法的内容是准确的
相同,除了执行
操作及其参数。

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

仅使用空值进行链接是行不通的,因为传递的委托不匹配。您可以做的就是将传递的操作/函数包装在 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();
}

The content of the methods are exactly
the same, except for the execution of
the action and its parameters.

That screams for using a higher order function, but since you already parameterized all the bits that are changing (execution of the action and its parameters) you're already there. Sorry, looks like you'll have to implement these overloads manually.

Just chaining through using nulls won't work since the delegates passed don't match. What you could do is wrap the passed action/func inside a lambda to peel off additional arguments:

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();
}
笑咖 2024-09-22 00:19:49

这实际上是最好的方法(请记住约翰尼斯的观点,您也可以使用更高阶的函数),因为它是最类型友好的(委托将自动与正确数量和类型的参数相匹配)并且确实不需要任何麻烦的 DynamicInvoke 调用。

但是,您最后的方法定义是有问题的。 Action 本质上不接受任何参数,因此它不会与 params object[] 参数配合良好。如果你想要一个接受可变数量参数的最终重载,我会选择 DynamicInvoke 毕竟,只是为了这个方法调用:

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

但是为了扩展 Johannes 所说的内容,我认为他基本上是得到这样的东西:

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

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

This is actually the best approach (keeping in mind Johannes's point that you could've also used a higher order function), as it is the most type-friendly (delegates will automatically be matched with the correct number and types of arguments) and does not require any bothersome DynamicInvoke calls.

Your last method definition is problematic, however. An Action by its very nature does not accept any parameters, so it isn't going to play nice with a params object[] argument. If you want a final overload that accepts a variable number of arguments, I'd go with DynamicInvoke after all, just for this method call:

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

But to expand on what Johannes was saying, I think he was basically getting at something like this:

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

And so on -- in other words, what you've already done, but in a general context so that the code is reusable in other places.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文