自我调用匿名函数

时间:2013-03-07 18:29:25

标签: c# anonymous-function anonymous-methods self-invoking-function

在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}}

2 个答案:

答案 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#的目标是避免这种歧义。