为什么lambdas可以转换为表达式而方法组不是?

时间:2013-04-07 18:21:15

标签: c# c#-4.0 lambda

LINQPad示例:

void Main()
{
    One(i => PrintInteger(i));
    One(PrintInteger);

    Two(i => PrintInteger(i));
    // Two(PrintInteger); - won't compile
}

static void One(Action<int> a)
{
    a(1);
}

static void Two(Expression<Action<int>> e)
{
    e.Compile()(2);
}

static void PrintInteger(int i)
{
    Console.WriteLine(i);
}

取消注释Two(PrintInteger);行会导致错误:

  

无法转换为&#39;方法组&#39;至   &#39;&System.Linq.Expressions.Expression LT; System.Action&LT; INT&GT;&GT;&#39;

这类似于Convert Method Group to Expression,但我对&#34;为什么感兴趣。&#34;我理解Features cost money, time and effort;我想知道是否有更有趣的解释。

3 个答案:

答案 0 :(得分:8)

因为,为了获得表达式树,我们需要在(未编译的)形式中表示该方法。 Lambda表达式在源代码中是本地可用的,因此始终可用于未编译。但是方法可能不是来自当前程序集内部,因此可能只能以编译形式提供。

当然,C#编译器可以反编译程序集的IL代码来检索表达式树,但正如您所提到的,实现功能需要花钱,这个特殊功能并不简单,而且好处不明确。

答案 1 :(得分:2)

原则上没有理由。它可以这样做。编译器可以在转换之前自己创建lambda(这显然总是可行的 - 它知道被调用的确切方法,因此它可以从其参数创建一个lambda)。

但有一个问题。 lambda参数的名称通常硬编码到正在生成的IL中。如果没有lambda,则没有名字。但编译器可以创建一个虚拟名称,也可以重用被调用方法的名称(它们始终以.NET汇编格式提供)。

为什么C#团队决定不启用此功能?想到的唯一原因是他们想把时间花在别的地方。我赞赏他们做出这个决定。我宁愿拥有LINQ或async而不是这个模糊的功能。

答案 2 :(得分:0)

One示例中,您隐式创建了Action<int>委托。它与:

相同
One( new Action<int>( PrintInteger ) );

我相信这是用于改进订阅事件语法的语言。

同样的事情不会发生在Expression<T>上,这就是你的第二个例子不能编译的原因。


编辑:

它被称为“方法组转换”。这是在C#规范 - 第6.6节

  

从方法组(第7.1节)到兼容的委托类型

存在隐式转换(第6.1节)