编译器没有绑定到正确的泛型方法重载

时间:2013-03-21 02:06:21

标签: c# compiler-errors type-inference overloading

通常,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 )Method( "", (Action<int, int>)Handler )中更明确地调用来编译它。但为什么这有必要呢?

1 个答案:

答案 0 :(得分:6)

让我们看看安东尼的建议,并考虑一下:

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是字符串。什么是U?

这一点非常重要:在我们知道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) { }
}

工作正常。我们推断T是字符串,现在我们可以对M进行重载决策,确定M表示double M(string s),现在我们知道U是双精度。