【问题标题】:Method resolution in Comparer比较器中的方法解析
【发布时间】:2010-08-05 08:58:57
【问题描述】:

考虑以下基本类布局:

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# 语言规范中描述的重载决议规则的基本理解,我似乎无法推断出这种行为。

有人可以帮我解释一下吗?

【问题讨论】:

标签: c# overloading derived


【解决方案1】:

Base 对它的派生类一无所知 - 所以在 Base 中只有 一个 CompareTo 方法,并且会被无条件调用。

重点是重载决议发生在编译时,此时没有可用的Base 引用的实际类型信息。你需要覆盖Derived中的方法,而不是重载它:

public class Derived : Base
{
  public override int CompareTo(Base other)
  {
    //Do comparison
  }  
}

另外标记Base.CompareTo方法virtual

请注意,这不再实现IComparable&lt;Derived&gt;。您也可以这样做,但与您的目的无关。

【讨论】:

  • 感谢您的努力。我试图聪明并通过在 x 和 y 都是派生实例的特定场景中使用重载来防止 CompareTo(Base) 上的虚拟/覆盖实现。看来我毕竟不是那么聪明:)
【解决方案2】:

重载解决不是这里发生的事情。你有两个独立的方法:它们的全名是IComparable&lt;Base&gt;.CompareToIComparable&lt;Derived&gt;.CompareTo

BaseComparer 唯一知道如何调用的是IComparable&lt;Base&gt;.CompareTo。它对IComparable&lt;Derived&gt;一无所知。

在您的应用程序中,将BaseDerived 进行比较是否有意义——也就是说,可以说Base 出现在Derived 之前或之后?

  • 如果是这样,您最好只使用IComparable&lt;Base&gt;,甚至是非泛型IComparable,并准备检查子类中的类型
  • 如果不是,您应该考虑将 Base 抽象化,并且仅在叶类上实现 IComparable&lt;T&gt;

【讨论】:

  • 所以我现在明白了。就我而言,比较 Base 和 Derived 实例是有意义的。我试图变得聪明,只需要编写一个单独的 CompareTo 实现,以防必须进行更微妙的比较(即,两者都是派生实例)并且对于所有其他情况,只需让重载解决方案退回到Base.CompareTo 中的充分比较。唉... :)
【解决方案3】:

IComparable&lt;Base&gt;IComparable&lt;Derived&gt;是两种不同的类型,所以Derived中的两个方法CompareTo映射到了两个不同的槽上。由BaseComparer 调用的CompareTo 调用IComparable&lt;Base&gt; 的方法。您可以将 Base 中的 CompareTo(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);
    }
}

【讨论】:

    猜你喜欢
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多