为什么Funcs不接受超过16个参数?

时间:2011-09-27 03:52:17

标签: c# .net generics functional-programming arguments

由于Javascript是我最熟练的语言,我熟悉将函数用作第一类对象。我原以为C#缺少这个功能,但后来我听说FuncAction以及delegate,我觉得这很棒。

例如,您可以声明一个Func连接两个字符串并在它们之间放置一个空格,如下所示:

Func<string, string, string> concat = (a,b) => a + " " + b;

当你输入

时我注意到了
Func<

IntelliSense显示它有17个重载:

delegate System.Func<out TResult>
delegate System.Func<in T, out TResult>
delegate System.Func<in T1, in T2, out TResult>
...snip...
delegate System.Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>
这让我开怀大笑。我查看Func Func并再次笑了起来。这让我尝试用17个参数声明Using the generic type 'System.Func<TResult>' requires 1 type arguments。它会导致错误(Func)。

我同意,拥有一个接受超过16个参数的Func可能不是一个好主意。即便如此,这似乎是Func实施的一种愚蠢方式。它需要记录17个简单的不同重载。这是它真正需要知道的全部内容:最后一个类型参数是返回类型,并且它之前的所有类型参数都是参数类型。

如果我想创建一个超过16个参数的Func,我该怎么办?为什么还有限制?为什么C#不能让你用任意数量的参数声明{{1}}?

6 个答案:

答案 0 :(得分:18)

你希望C#缺少像variadic type arguments这样的东西。 C#需要修复泛型类型的arity,因此FuncActionTuple类型会出现令人发指的扩散。

如果你是语言购物,这个功能是在C ++ 11中添加的,但你应该只使用jQuery。 : - )

答案 1 :(得分:15)

您可以定义所需的任何委托。因此,具有20个参数的Func将被定义为:

public delegate R Func<
    P0, P1, P2, P3, P4, P5, P6, P7, P8, P9,
    P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R>(
        P0 p0, P1 p1, P2 p2, P3 p3, P4 p4,
        P5 p5, P6 p6, P7 p7, P8 p8, P9 p9,
        P10 p10, P11 p11, P12 p12, P13 p13, P14 p14,
        P15 p15, P16 p16, P17 p17, P18 p18, P19 p19);

然后您可以像这样使用它:

Func<
        int, int, int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int, int, int, int> f = (
            p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
            p11, p12, p13, p14, p15, p16, p17, p18, p19) =>
                p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10
                    + p11 + p12 + p13 + p14 + p15 + p16 + p17 + p18 + p19;

var r = f(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);

C#还允许您在任何委托上使用lambda语法,因此您也可以这样做:

public delegate R ArrayFunc<P, R>(params P[] parameters);

然后像这样使用它:

ArrayFunc<int, int> af = ps => ps.Sum();

var ar = af(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);

这是该语言非常灵活和强大的功能。

答案 2 :(得分:7)

我想我明白了 - 你可以用JavaScript和函数(参数)做些什么,但它也不是静态类型的。

但请注意,无论如何,你在函数式编程中绝不需要多个参数。你可以通过返回另一个函数来链接尽可能多的参数(这是FP中的一个常见特性,并且通常用于限制JS中可用的技术,但只是稍微弯曲系统)。

当然这在C#中很尴尬:

Func<A1,Func<A2,Func<A3,...<Func<An,Result>>...> 
  x1 =>
    (x2 => 
      (x3 => 
        ... 
          (xn => 
              { /*return soomething */ }
  ))...);

但这就是F#的用途;)当然,你永远不应该创建一个带有多个参数的函数(低于16的方式!)无论如何。

答案 3 :(得分:1)

您可以使用超过16个参数创建自己的委托。或者您可以使用Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(或任何其他数据结构)作为参数。

答案 4 :(得分:1)

Why is there a limit anyway?

有意见认为功能可能不应超过3个参数。如果它有更多,它变得越来越难以理解。当然这可能不是C#中这种方式的原因,但毕竟这种限制可能并不是一件坏事。

我认为即使这个16的限制太多了,并且已经鼓励糟糕的设计选择。

答案 5 :(得分:1)

System.Func代表很可能归功于BCL团队......他们意识到包含有限数量的预定义通用代表会很方便(甚至在很多情况下都需要)。

要做你说的话...即Func委托的无限数量的通用参数需要语言改变..责任在于c#和vb.net团队(以及其他人可能)将语言改为允许这个。

也许,在某些时候,如果这个功能的好处超过预定义少数Func代表的成本,这比其他语言更改更重要(并且它不是一个重大改变)相关团队我的工具无限的通用参数..可能不会有一段时间了!