C# 自调用匿名函数

C# 自调用匿名函数,c#,anonymous-function,anonymous-methods,self-invoking-function,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 => x)(42); 但是,每个版本都有错误: 应为方法名 是否不支持自调用匿名方法(由于显式禁止或类型推断

在JavaScript中,经常会看到自调用函数:

var i = (function(x) {
    return x;
})(42);

// i == 42
虽然我肯定不会比较语言,但我认为这样的构造可以翻译为C#,提供了支持的语言版本:

var i = (delegate(int x) {
    return x;
})(42);
或:

甚至:

var i = (x => x)(42);
但是,每个版本都有错误:

应为方法名

是否不支持自调用匿名方法(由于显式禁止或类型推断的不可能性),或者我的尝试中是否存在错误

我大胆猜测,因为没有方法声明(
Func
)可以推断类型,所以它无法对隐含类型进行排序,因为我想按名称调用声明的方法,而且语法真的搞错了


勘误表

在这个问题被淹没之前:

var i = new Func<int, int>(x => x)(42);
var x=((Func)(y=>y*2))(10);

问题是,当编译器看到
y=>y*2
时,默认情况下会将其分类为
表达式,而不是
Func
,除非有上下文信息让它知道它应该是
Func
。通过将它转换为
Func
我们为它提供了所需的上下文。

我想C团队的人可以给出更好的答案,但我尝试了我的方法。这里的问题不是这是否是一个最佳实践,而是它是否可能,如果不可能,为什么

让我们从你要写的内容开始:

var i = (x => x)(42);
非常简单,您将一个整数(
42
)传递给lambda,它对其进行处理并返回相同的值。它的参数是一个整数(从其用法推断),它返回一个整数(从表达式推断),而
i
是另一个整数(从返回值推断)

不幸的是,这在第一步就被打破了。让我:

编译器试图根据使用lambda表达式的上下文计算出lambda表达式的参数类型

这是什么意思?实际上,编译器需要一些信息,但它只能使用:

  • (Func)(x=>x))
    newfunc(x=>x)
    中那样的显式强制转换、构造函数或声明。此处所需的类型是使用所需的最终类型给出或推断的
  • 赋值(同样是因为可以推断最终类型),如:
    Func f=(x=>x)
在您的情况下,编译器必须从其参数推断函数类型,这是不可能的,因为参数是根据表达式验证的,反之亦然

为什么这在C#中不可能?因为
(x=>x)
只是一个委托,那么它可以是接受整数参数的任何委托(如果我们假设编译器可以从rhs推断lhs并根据lhs验证rhs)并返回另一个整数。实际上,在C#中不允许在委托之间进行转换,因此表达式无效(即使此特殊委托不会分配给任何变量,并且将来也不会使用)。它可以是
Func
Expression
或任何其他委托(对于
bool
参数,它甚至可以是
谓词

当然,这是一个C#设计决策,同样的表达式——例如——在VB.NET中是完全有效的:

 Dim i = (Function(x) x)(42)

不同的语言,不同的规则需要遵守,C#的目标是避免这种歧义。

考虑一下为什么您需要javascript中的这种结构,并将这种概念应用到C#。asawyer虽然我欣赏对您的评论采用“教人钓鱼”的方法,但还是希望您能稍加阐述;)在javascript中,自调用函数究竟能实现什么?@Brandon我想,关键是它是否是一件好事。如果您编写一个长的匿名函数,那么如果您编写一个真正命名的函数,您的代码可能会更清晰。@Bracketworks所以您需要一个可以包含私有变量值的对象,它可以公开属性和其他函数?我认为在c#…
vari=newfunc(x=>x)(42)中有一个词来表示这种类型的构造语法也是有效的。@Caramiriel:啊,是的,我从来没有考虑过使用构造函数语法:),如果确实是这样的话;编译器看到
x=>x
并将其解释为一个表达式,那么为什么
委托
替代方案不起作用呢?@Bracketworks:我认为这是因为用
delegate
声明的匿名方法在分配给某个对象之前不是完全类型化的。同样,它需要上下文。这项工作:
((Func)委托(inty){returny y*2;})(10)。看见
var x = ((Func<int, int>)(y => y * 2))(10);
var i = (x => x)(42);
 Dim i = (Function(x) x)(42)