C#通用重载方法分派模糊

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());
}

无论如何,为什么编译器不会警告我,甚至为什么它可以编译通过? 非常感谢任何回答。


如果您期望从调用中返回一个值,例如 var result = concreteB.Add(new ConcreteA());,会发生什么? - Tomas Aschan
1
因为你的泛型方法有一个返回类型为“T”,而另一个方法的类型为“void”。编译器可以区分它们。 - Mohnkuchenzentrale
编译器会报错,因为它无法将 void 赋值给隐式类型变量 var - Sebastian
3个回答

2
它遵循C# 4规范第7.5.3.2节中的规则("更好的函数成员")。
首先(在确定两种方法都是可应用的后),我们需要检查参数类型到形参类型的转换。在这种情况下,它相对简单,因为只有一个参数。无论参数类型转换到形参类型,都不能被视为“更好”,因为它们都从ConcreteA转换到IfaceA。因此,它继续进行下一组标准,包括以下内容:
否则,如果 MP 拥有比 MQ 更具体的参数类型,则 MP 优于 MQ。让 {R1,R2,…,RN} 和 {S1,S2,…,SN} 分别代表 MP 和 MQ 的未实例化和未展开的参数类型。如果对于每个参数,RX 不比 SX 不具体,并且对于至少一个参数,RX 比 SX 更具体,则 MP 的参数类型比 MQ 更具体。

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

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


好的,非常感谢。我想这意味着我会阅读那个规范。我只是一个Java转换者,不得不在这个项目中使用C#。虽然事实上我认为它更有用,但我觉得任何功能都会增加一些边缘情况... - Sebastian

1

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

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

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

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

但是为什么void Add(IfaceA a)会更具体呢?这是因为我没有使用返回的结果吗?此外,您知道是否有编译器选项可以产生警告吗? - Sebastian
@sebgod:你可以使用#warning指令来发出编译器警告。 - Tomas Aschan
如果我选择 IfaceA x = concreteB.Add(new ConcreteA());,代码将无法编译:IFaceA和void之间不能隐式转换。 - Sebastian
正如您所看到的,这是我在SO上的第一个问题,我很遗憾不能为您的答案投票,因为我需要15个积分,我想今天早上的咖啡不太好^^ - Sebastian
@Tomas,我所说的警告是指编译器会告诉我这个问题,而不是我想发出警告(这是一个悄无声息的代码破坏)。 - Sebastian
显示剩余2条评论

1
这有点让我想起Jon Skeet's BrainTeaser中的“类型推断”。 如果你不想信任编译器,你可能想通过调用Add<ConcreteA>(new ConcreteA())来强制它的选择。

这就是我的老师经常告诉我的,永远不要相信你的编译器。 - Sebastian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接