0

通常,C# 编译器在方法绑定和类型参数推断方面很聪明。但我似乎把它难住了。

class Obj
{
    void Handler( int a, int b ) { }

    Obj() { Method( "", Handler ); }

    public void Method<T>( T t, Action<T> action ) { }

    public void Method<T, U>( T t, Action<U, U> action ) { }
}

Method调用导致编译器错误:

参数 2:无法从“方法组”转换为“System.Action”。

为什么编译器没有注意到调用适合第二个重载?我可以通过在Method<string, int>( "", Handler )or中使调用更明确来编译它Method( "", (Action<int, int>)Handler )。但为什么这是必要的?

4

1 回答 1

6

让我们采纳 Anthony 的建议并考虑一下:

class Obj
{
    void Handler( int a, int b ) { }
    Obj() { Method( "", Handler ); }
    public void Method<T, U>( T t, Action<U, U> action ) { }
}

重载解析失败。为什么?好吧,我们必须推断出 T 和 U。显然 T 是字符串。什么是你?

这一点很重要:我们在知道 Handler 是什么之后推断出 U 是什么。现在,您可能会说我们知道 Handler 是什么,因为它可能只有一件事。但是没有 C# 规则说,如果方法组中只有一个方法,它会自动赢得重载决议游戏。规则是 Handler 的含义是通过在与 Handler 关联的方法组上运行重载决议来确定的。重载决议考虑了参数,我们没有任何 Handler 的参数,因为我们可能拥有的唯一参数列表是 (U, U),而 U 是我们首先要确定的。

所以重载决议在这里失败了。现在,如果我们有:

class Obj
{
    double M(string s) { }
    Obj() { Method( "", M ); }
    public void Method<T, U>(T t, Func<T, U> f) { }
}

That works fine. We infer T is string, and now we can do overload resolution on M, determine that M means double M(string s), and now we know that U is double.

于 2013-03-21T04:34:38.783 回答