Verfahren Auflösung in Comparer
-
26-09-2019 - |
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?
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-genericIComparable
, und bereit sein, Arten zu überprüfen in Subklassen - Wenn nicht, sollten Sie überlegen,
Base
abstrakt zu machen, und nurIComparable<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);
}
}