5

我正在使用 Visual Studio 2012 Update 1 和 .NET 4.5 这里是代码。

void Test(Action a) { }
void Test(Func<int> a) { }
void TestError()
{
    bool throwException = true;
    //Resolves to Test(Action a)
    Test(() =>
    {
    });
    //Resolves to Test(Action a)
    Test(() =>
    {
        if (throwException) throw new Exception();
    });
    //Resolves to Test(Func<int> a)
    //(This seems like a bug since there is no return value)
    Test(() =>
    {
        throw new Exception();
    });
    //Resolves to Test(Action a)
    //(With warning unreachable code detected)
    Test(() =>
    {
        throw new Exception();
        return; //unreachable code detected
    });
}

似乎最后一个函数调用错误地解析为 Func 而不是 Action,它与无条件抛出异常有关。

这是一个BUG吗?谢谢。

4

1 回答 1

7

好吧,对我来说,两者都是有效的候选人似乎是合理的。换句话说,我认为将 转换为和() => { throw new Exception(); }都很好。在这两种情况下,方法的结尾都是不可到达的——将它放入一个普通的命名方法中是完全有效的,如下所示:Func<int>Action

public int GoBang()
{
    throw new Exception();
}

然后写:

Func<int> foo = GoBang;

因此,从 lambda 表达式到两者的转换Func<int>都是Action有效的。我们现在需要选择使用哪种方法。这在规范第 7.5.3.2 节(更好的功能成员)中指定,其中包括:

对于至少一个论点,从 E x到 P x的转换优于从 E x到 Q x的转换

此时,第 7.5.3.3 节(更好地从表达式转换)开始:

如果以下至少一项成立,则C 1是比 C 2更好的转换:

  • [...]
  • E 是一个匿名函数,T 1是委托类型 D 1或表达式树类型 Expression<D 1 >,T 2是委托类型 D 2或表达式树类型 Expression<D 2 >,其中之一以下持有:

    • [...]
    • D 1和 D 2具有相同的参数列表,并且以下条件之一成立:
    • D 1有一个返回类型 Y,而 D 2是 void 返回。

所以这就是为什么Func<int>优先于Action......编译器做正确的事情。

于 2013-02-21T13:51:12.610 回答