22

在 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>可以推断类型的方法声明( .


勘误表

在这个问题被淹没之前:

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
    }(),
};
4

2 回答 2

20
var x = ((Func<int, int>)(y => y * 2))(10);

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

于 2013-03-07T18:33:21.863 回答
11

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

让我们从你要写的开始:

var i = (x => x)(42);

非常简单,您将整数 ( 42) 传递给 lambda,它会使用它并返回相同的值。它的参数是一个整数(从它的用法推断),它返回一个整数(从表达式推断)并且i是另一个整数(从返回值推断)。

不幸的是,这在第一步就被打破了。让我引用大乔恩

编译器尝试根据使用它的上下文来计算 lambda 表达式的参数类型。

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

  • 显式转换、构造函数或声明,如 in(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参数,它甚至可能是 bee Predicate<bool>)。

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

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

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

于 2013-03-08T08:48:59.443 回答