37

给定一个DoSomething采用(无参数)函数并以某种方式处理它的方法。有没有比下面的代码片段更好的方法来为带参数的函数创建“重载”?

public static TResult DoSomething<TResult>(Func<TResult> func)
{
    //call func() and do something else
}

public static TResult DoSomething<T0, TResult>(
    Func<T0, TResult> func,
    T0 arg0)
{
    return DoSomething(() => func(arg0));
}

public static TResult DoSomething<T0, T1, TResult>(
    Func<T0, T1, TResult> func,
    T0 arg0, T1 arg1)
{
    return DoSomething(arg => func(arg, arg1), arg0);
}

public static TResult DoSomething<T0, T1, T2, TResult>(
    Func<T0, T1, T2, TResult> func,
    T0 arg0, T1 arg1, T2 arg2)
{
    return DoSomething(arg => func(arg, arg1, arg2), arg0);
}
4

3 回答 3

39

编辑:如评论中所述,这是部分应用而不是柯里化。我写了一篇关于我对差异的理解的博客文章,人们可能会觉得有趣。

好吧,它并没有特别的不同 - 但我会将咖喱部分与“调用 DoSomething”部分分开:

public static Func<TResult> Apply<TResult, TArg> (Func<TArg, TResult> func, TArg arg)
{
    return () => func(arg);
}

public static Func<TResult> Apply<TResult, TArg1, TArg2> (Func<TArg1, TArg2, TResult> func,
                                                          TArg1 arg1, TArg2 arg2)
{
    return () => func(arg1, arg2);
}

// etc

然后:

DoSomething(Apply(foo, 1));

这样,您可以在其他情况下重用柯里化代码 - 包括您不想立即调用新返回的委托的情况。(例如,您以后可能想更多地咖喱它。)

于 2009-01-04T20:02:52.307 回答
3

@Jon Skeet 的答案是正确的,但是手动编写所有可能的超载是疯狂的,因此您可以使用像Curryfy这样的库来为您完成这项工作。Curryfy 库特别公开了 Curry、UnCurry 和 ApplyPartial 扩展方法,有很多重载。

于 2020-02-22T12:29:10.963 回答
0

这是允许使用dynamic(如 js 中的 Curry)编写无限调用函数的方法:

dynamic Sum(int a)
{
    Console.WriteLine(a);
    return new Func<int, dynamic>(b => Sum(a + b));
}

如果你这样称呼它Sum(2)(3)(4)(10),输出将是:

2
5
9
19
于 2021-04-17T12:31:15.213 回答