c#通用重载方法调度模糊

时间:2010-05-18 07:11:23

标签: c# methods generics overloading dispatch

我刚刚遇到方法调度模糊的情况,并想知道是否有人可以解释编译器(.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());
}

在任何情况下,为什么编译器不会警告我,甚至为什么编译? 非常感谢你的任何答案。

3 个答案:

答案 0 :(得分:2)

遵循C# 4 specification(“更好的功能成员”)第7.5.3.2节中的规则。

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

  

否则,如果MP更具体   参数类型比MQ,然后MP是   比MQ更好。设{R1,R2,...,RN}   并且{S1,S2,...,SN}代表   未实例化和未扩展   MP和MQ的参数类型。 MP的   参数类型比具体更具体   MQ的if,对于每个参数,RX不是   比SX更不具体,而且,对于   至少有一个参数,RX更多   特定于SX:特定于SX:

     
      
  • 类型参数的特定性低于非类型参数。
  •   
  • ...
  •   

所以即使转换同样好,但直接使用IfaceA(而不是通过委托)的重载被认为是“更好”,因为IfaceA类型的参数是比T类型的参数更具体。

没有办法让编译器警告这种行为 - 这只是正常的重载解析。

答案 1 :(得分:1)

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

如果你这样打电话会怎么样:

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

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 

答案 2 :(得分:1)

这有点让我想起Jon Skeet's BrainTeaser中的“类型推断a-go-go”。 如果您不想信任编译器,可能需要通过调用Add<ConcreteA>(new ConcreteA())

来强制选择它