在编译时解决错误的函数BUG?

Aar*_*ack 5 c# delegates

我正在使用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
    });
}
Run Code Online (Sandbox Code Playgroud)

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

这是一个BUG吗?谢谢.

Jon*_*eet 7

嗯,我认为两者都是有效的候选人似乎是合理的.换句话说,我觉得() => { throw new Exception(); }将两者转换为Func<int>Action.在这两种情况下,方法的结尾都是无法访问的 - 将它放入正常的命名方法是完全有效的,如下所示:

public int GoBang()
{
    throw new Exception();
}
Run Code Online (Sandbox Code Playgroud)

然后写:

Func<int> foo = GoBang;
Run Code Online (Sandbox Code Playgroud)

因此,从转换的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或表达式树类型表达式<D 2 >,其中一个以下是:

    • [...]
    • D 1和D 2具有相同的参数列表,并且具有以下之一:
    • D 1具有返回类型Y,并且D 2返回空白.

所以这就是为什么Func<int>首选Action...编译器正在做正确的事情.

  • C#5规范的相关部分似乎是7.5.3.3,其中声明如果"D1具有返回类型Y,则匿名函数到委托类型D1的转换优于具有相同参数列表的委托类型D2,并且D2无效返回". (4认同)