Comparer中的方法解析

时间:2010-08-05 08:58:58

标签: c# overloading derived

考虑以下基本类布局:

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#语言规范中描述的重载决策规则的基本理解来推断出这种行为。

有人可以为我阐明这个吗?

3 个答案:

答案 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>.CompareToIComparable<Derived>.CompareTo

BaseComparer知道如何致电的唯一一个是IComparable<Base>.CompareTo。它对IComparable<Derived>一无所知。

在您的应用中,将BaseDerived进行比较是否有意义 - 也就是说,可以说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}}