在JavaScript中,看到自调用函数并不罕见:
var i = (function(x) {
return x;
})(42);
// i == 42
虽然我当然没有比较语言,但我认为这样的结构可以翻译成C#,只要提供支持的语言版本:
var i = (delegate(int x) {
return x;
})(42);
或者:
var i = ((x) => {
return x;
})(42);
甚至:
var i = (x => x)(42);
但是,每个版本都有错误:
预期的方法名称
是否不支持自调用匿名方法(由于显式禁止或类型推断不可能),或者我的尝试是否有错误?
我冒昧地猜测,因为没有方法声明( Func<T,T>
)可以推断出类型,它无法理清隐含的类型,数字I意思是按名称调用声明的方法,并且真正搞砸了语法。
勘误表
在这个问题充斥着:
之前var i = new Func<int, int>(x => x)(42);
我应该说我希望利用类型推断,但我认为这可能是不可能的,因为过度 - 隐藏。
所以,稍微澄清一下这个问题;我们知道我们可以var i = new Func<int, int>(x => x)(42);
但是如果不创建Func
的实例或转换为var o = new {
PropertyA = () => {
// value computation
}(),
PropertyB = () => {
// value computation
}(),
};
,这可能吗?
使用例
对于那些好奇的人(或关注),用例是这样的:
{{1}}
答案 0 :(得分:15)
var x = ((Func<int, int>)(y => y * 2))(10);
问题在于,当编译器看到y => y * 2
时,它默认将其归类为Expression
而不是Func
,除非有一些上下文信息让它知道它应该是一个Func
。通过将其转换为Func
,我们可以为其提供所需的上下文。
答案 1 :(得分:9)
我想C#团队中的某个人可以提供更好的答案,但我会尝试拍摄。这里的问题不是,如果这是最佳实践,但如果可能,如果不是,为什么。
让我们从你要写的内容开始:
var i = (x => x)(42);
非常简单,您将一个整数(42
)传递给lambda,它会与它一起播放并返回相同的值。它的参数是一个整数(根据其用法推断),它返回一个整数(从表达式推断),i
是另一个整数(从返回值推断)。
不幸的是,这在第一步中被打破了。让我cite big Jon:
编译器尝试根据lambda表达式使用的上下文计算出lambda表达式的参数类型。
这是什么意思?实际上编译器需要一些信息,但它只能使用:
(Func<int, int>)(x => x))
或new Func<int, int>(x => x)
中的明确演员,构造函数或声明。此处所需的类型是使用所需的最终类型给出或推断的。Func<int, int> f = (x => x);
在您的情况下,编译器必须从其参数推断出函数类型,并且这是不可能的,因为参数是针对表达式验证的,反之亦然。
为什么在C#中无法做到这一点?因为(x => x)
只是一个委托,所以它可以是接受整数参数的任何委托(如果我们假设编译器可以从rhs推断出lhs并根据lhs验证rhs并返回另一个整数。实际上,在C#中不允许代理之间的转换,因此表达式无效(即使此特殊委托不会分配给任何变量,也不会用于未来)。它可以是Func<int, int>
或Expression<Func<int, int>>
或任何其他代表(对于bool
参数,它甚至可能是Predicate<bool>
)。
当然这是一个C#设计决策,例如,VB.NET中的相同表达式完全有效:
Dim i = (Function(x) x)(42)
不同的语言,不同的服从规则,C#的目标是避免这种歧义。