7

我刚刚遇到方法分派不明确的情况,想知道是否有人可以解释编译器(.NET 4.0.30319)在什么基础上选择要调用的重载

interface IfaceA
{

}

interface IfaceB<T>
{
    void Add(IfaceA a);
    T Add(T t);
}

class ConcreteA : IfaceA
{

}

class abstract BaseClassB<T> : IfaceB<T>
{
    public virtual T Add(T t) { ... }
    public virtual void Add(IfaceA a) { ... }
}

class ConcreteB : BaseClassB<IfaceA>
{
    // does not override one of the relevant methods
}

void code()  
{
    var concreteB = new ConcreteB();

    // it will call void Add(IfaceA a)
    concreteB.Add(new ConcreteA());
}

无论如何,为什么编译器不警告我,甚至为什么编译?非常感谢您的任何回答。

4

3 回答 3

2

它遵循C# 4 规范(“更好的函数成员”)第 7.5.3.2 节中的规则。

首先(好吧,在看到这两种方法都适用之后)我们需要检查从参数类型到参数类型的转换。在这种情况下,它相当简单,因为只有一个论点。参数类型到参数类型的转换都不是“更好”,因为两者都从 转换ConcreteAIfaceA. 因此,它转到下一组标准,包括:

否则,如果 MP 比 MQ 具有更具体的参数类型,则 MP 优于 MQ。令 {R1, R2, ..., RN} 和 {S1, S2, ..., SN} 表示 MP 和 MQ 的未实例化和未扩展的参数类型。MP 的参数类型比 MQ 的更具体,如果对于每个参数,RX 不比 SX 更具体,并且,对于至少一个参数,RX 比 SX 更具体:具体比 SX:

  • 类型参数不如非类型参数具体。
  • ...

因此,即使转换同样好,IfaceA直接使用(而不是通过委托)的重载也被认为是“更好的”,因为 typeIfaceA的参数比 type 的参数更具体T

没有办法让编译器对这种行为发出警告——这只是正常的重载决议。

于 2010-05-18T07:29:56.080 回答
1

这在某种程度上让我想起了Jon Skeet 的 BrainTeaser中的“Type inference a-go-go” 。如果您不想信任编译器,您可能希望通过调用来强制其选择Add<ConcreteA>(new ConcreteA())

于 2010-05-18T07:27:30.200 回答
1

因为编译器首先选择最具体的。

如果你这样调用会发生什么:

void code()   
{ 
    var concreteB = new ConcreteB(); 

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 
于 2010-05-18T07:14:31.170 回答