[英]Why don't Funcs accept more than 16 arguments?
由于 Javascript 是我最精通的语言,所以我熟悉使用函数作为一等对象。 我原以为 C# 缺少这个功能,但后来我听说了Func
和Action
和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
的MSDN 文档,然后又笑了。 这让我尝试声明一个带有 17 个参数的Func
。 它会导致错误( Using the generic type 'System.Func<TResult>' requires 1 type arguments
)。
我同意拥有一个接受超过 16 个参数的Func
可能不是一个好主意。 即便如此,对于Func
,这似乎是一种笨拙的实现方式。 它需要记录 17 个不同的重载。 这就是它真正需要知道的全部内容:最后一个类型参数是返回类型,它之前的所有类型参数都是参数类型。
那么如果我想创建一个超过 16 个参数的Func
该怎么办呢? 为什么总有限制? 为什么 C# 不能让你用任意数量的参数声明一个Func
?
你希望像 C# 缺少的可变参数类型参数。 C# 需要固定泛型类型的数量,因此Func
、 Action
和Tuple
类型的数量令人发指。
如果您正在购买语言,此功能是在 C++11 中添加的,但您可能应该只使用 jQuery。 :-)
您可以定义您需要的任何委托。 所以一个带有 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);
这是该语言的一个非常灵活和强大的特性。
我想我明白 - 你可以用 JavaScript 和函数(参数)做什么是非常整洁的,但它也不是静态类型的。
但请注意,无论如何,在函数式编程中永远不需要多个参数。 您可以通过返回另一个函数来链接尽可能多的参数(这是 FP 中的一个常见特征,并且在 JS 中也可用的技术中大量使用,但只是稍微弯曲系统)。
当然,这在 C# 中是错误的:
Func<A1,Func<A2,Func<A3,...<Func<An,Result>>...>
x1 =>
(x2 =>
(x3 =>
...
(xn =>
{ /*return soomething */ }
))...);
但这就是 F# 的用途 ;) 当然,无论如何你都不应该创建一个参数超过几个(远低于 16!)的函数。
您可以使用超过 16 个参数创建自己的委托。 或者您可以使用Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>
(或任何其他数据结构)作为参数。
Why is there a limit anyway?
有意见认为函数可能不应该有超过 3 个参数。 如果它有更多,它变得越来越难以理解。 当然这可能不是 C# 中会这样的原因,但这种限制终究不是什么坏事。
我认为即使是 16 的这个限制也太多了,并且已经在鼓励糟糕的设计选择。
多亏了 BCL 团队,System.Func 委托才可能存在。他们意识到包含有限数量的预定义泛型委托会很方便(甚至在很多情况下都需要)。
要按照您说的去做.. 即 Func 委托的无限数量的泛型参数需要更改语言.. c# 和 vb.net 团队(以及其他可能的团队)都有责任更改语言以允许这样做。
也许,在某些时候,如果此功能的好处超过预定义少数 Func 委托的成本,并且这比其他语言更改更重要(并且它不是破坏性更改),那么相关团队将实现无限的通用参数.. 可能不会有一段时间了!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.