我刚刚遇到方法调度模糊的情况,并想知道是否有人可以解释编译器(.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());
}
在任何情况下,为什么编译器不会警告我,甚至为什么编译? 非常感谢你的任何答案。
答案 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())