考虑以下基本类布局:
public class Base : IComparable<Base>
{
public int CompareTo(Base other)
{
//Do comparison
}
}
public class Derived : Base, IComparable<Derived>
{
public int CompareTo(Derived other)
{
//Do comparison
}
}
public class BaseComparer : IComparer<Base>
{
public int Compare(Base x, Base y)
{
return x.CompareTo(y);
}
}
然后使用以下内容:
List<Base> thingies = new List<Base>
{
new Base(),
new Derived(),
new Derived()
};
thingies.Sort(new BaseComparer());
我期望Comparer在其x和y参数都是Derived实例的情况下调用Derived.CompareTo方法。
然而,情况并非如此,而且调用了Base.CompareTo,我一直在想为什么。我似乎无法通过对C#语言规范中描述的重载决策规则的基本理解来推断出这种行为。
有人可以为我阐明这个吗?
答案 0 :(得分:5)
Base
对其派生类一无所知 - 所以在Base
中只有一个 CompareTo
方法,并且无条件地调用它。
关键是重载解析发生在编译时,其中没有关于可用的Base
引用的实际类型的信息。您需要覆盖 Derived
中的方法,而不是重载:
public class Derived : Base
{
public override int CompareTo(Base other)
{
//Do comparison
}
}
另外标记Base.CompareTo
方法virtual
。
请注意,这不再实现IComparable<Derived>
。您也可以 这样做,但出于与您无关的目的。
答案 1 :(得分:1)
重载分辨率不是这里发生的事情。您有两种独立的方法:全名是IComparable<Base>.CompareTo
和IComparable<Derived>.CompareTo
。
BaseComparer
知道如何致电的唯一一个是IComparable<Base>.CompareTo
。它对IComparable<Derived>
一无所知。
在您的应用中,将Base
与Derived
进行比较是否有意义 - 也就是说,可以说Base
位于Derived
之前或之后?
IComparable<Base>
,甚至是非通用IComparable
,并准备检查子类中的类型Base
抽象化,并且只在叶子类上实现IComparable<T>
答案 2 :(得分:1)
IComparable<Base>
和IComparable<Derived>
是两种不同的类型,因此CompareTo
中的两个方法Derived
被映射到两个不同的广告位。 CompareTo
调用BaseComparer
调用IComparable<Base>
方法调用的CompareTo(Base)
。您可以在Base
中将virtual
表示为Derived
,并在public class Base : IComparable<Base>
{
public virtual int CompareTo(Base other)
{
// do comparison
}
}
public class Derived : Base, IComparable<Derived>
{
public int CompareTo(Derived other)
{
// do comparison
}
public override int CompareTo(Base other)
{
if (other is Derived)
return CompareTo((Derived) other);
return base.CompareTo(other);
}
}
中覆盖它以获得(部分)预期的行为。
{{1}}