Frage

Sehen Sie das folgende Basisklasse Layout:

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

und mit denen dann wie folgt:

List<Base> thingies = new List<Base>
{
  new Base(),
  new Derived(),
  new Derived()
};

thingies.Sort(new BaseComparer());

ich die Comparer erwartet die Derived.CompareTo Methode in solchen Situationen zu nennen, wo sowohl er die Parameter x und y-Instanzen abgeleitet werden.

Dies ist jedoch nicht der Fall und Base.CompareTo heißt statt und ich halte fragen, warum. Ich kann nicht scheinen, dieses Verhalten mit meinem Grundverständnis für die Überladungsauflösung Regeln abzuziehen, wie in der Sprache C # Spezifikation beschrieben.

Kann jemand etwas Licht auf das für mich?

War es hilfreich?

Lösung

Base weiß nichts von seinen abgeleiteten Klassen -. So in Base gibt es nur eine CompareTo Methode, und das bedingungslos aufgerufen wird,

Der Punkt ist, dass die Überladungsauflösung geschieht in Kompilierung , wo gibt es keine Informationen über die tatsächliche Art der Base Referenzen zur Verfügung. Sie müssen Überschreibung das Verfahren in Derived, nicht Überlastung es:

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

Und zusätzlich die Base.CompareTo Methode virtual markiert.

Beachten Sie, dass dies nicht implementiert IComparable<Derived> mehr. Sie können auch tun dies, aber für Ihren Zweck das ist unabhängig.

Andere Tipps

Die Überladungsauflösung ist nicht das, was hier passiert. Du hast zwei unabhängige Methoden. Ihre vollständigen Namen sind IComparable<Base>.CompareTo und IComparable<Derived>.CompareTo

Die einzige, die BaseComparer weiß, wie man Anruf IComparable<Base>.CompareTo ist. Er weiß nichts über IComparable<Derived>.

In Ihrer Anwendung ist es sinnvoll eine Base mit einem Derived vergleichen - das kann nur sagen, dass ein Base kommt vor oder nach einem Derived

  • Wenn ja, wäre man besser bleiben mit nur IComparable<Base> oder auch der nicht-generic IComparable, und bereit sein, Arten zu überprüfen in Subklassen
  • Wenn nicht, sollten Sie überlegen, Base abstrakt zu machen, und nur IComparable<T> auf Blattklassen Umsetzung

IComparable<Base> und IComparable<Derived> sind zwei verschiedene Typen, so dass zwei Methoden in CompareTo Derived auf zwei verschiedene Slots abgebildet werden. CompareTo aufgerufen durch BaseComparer ruft Methode von IComparable<Base>. Sie können CompareTo(Base) in Base als virtual bezeichnen und sie in Derived außer Kraft zu (teilweise) erwartetes Verhalten zu bekommen.

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);
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top