2010-08-05 17 views
1

considèrent la mise en page de la classe de base suivante:résolution de méthode Comparer

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

puis en utilisant ceux comme suit:

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

thingies.Sort(new BaseComparer()); 

j'attendais le comparateur être appeler la méthode Derived.CompareTo dans les situations dans lesquelles ses paramètres x et y sont des instances dérivées.

Cependant, ce n'est pas le cas et Base.CompareTo est appelé à la place et je me demande pourquoi. Je ne peux pas sembler déduire ce comportement avec ma compréhension de base des règles de résolution de surcharge comme décrit dans la spécification de langage C#.

Quelqu'un peut-il nous éclairer à ce sujet?

+1

Lire Eric Lipperts messages blog sur la résolution de surcharge - http://blogs.msdn.com/b/ericlippert/archive/tags/overload+resolution/ – Oded

Répondre

5

Base ne sait rien de ses classes dérivées - donc en Base il n'y a que une méthode CompareTo, et qui est appelé sans condition.

Le point est que la résolution de surcharge se produit à l'heure de compilation où il n'y a aucune information sur le type réel des références Base disponibles. Vous devez override la méthode Derived, pas surcharge il:

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

Et marquer en plus la méthode Base.CompareTovirtual.

Notez que cela n'implémente plus IComparable<Derived>. Vous pouvez également faire cela, mais pour votre but, c'est sans rapport.

+0

Thanx pour vos efforts. J'essayais d'être intelligent et d'empêcher l'implémentation de virtual/override sur CompareTo (Base) en utilisant la surcharge pour le scénario spécifique où x et y sont des instances dérivées. Il semble que je n'étais pas si intelligent après tout :) – Anton

1

La résolution de surcharge n'est pas ce qui se passe ici. Vous avez deux méthodes indépendantes: leurs noms complets sont IComparable<Base>.CompareTo et IComparable<Derived>.CompareTo. Le seul que BaseComparer sait appeler est IComparable<Base>.CompareTo. Il ne sait rien sur IComparable<Derived>.

Dans votre application, est-il logique de comparer un Base avec un Derived - qui est, peut dire qu'un Base vient avant ou après un Derived?

  • Si oui, vous feriez mieux de rester avec seulement IComparable<Base>, ou même le IComparable, et être prêt non générique pour vérifier les types dans les sous-classes
  • Dans le cas contraire, vous devriez envisager de faire Base abstraite, et que la mise en œuvre IComparable<T> sur les classes de feuilles
+0

Donc, je vois maintenant. Dans mon cas, il est logique de comparer les instances de base et dérivées. J'essayais d'être intelligent et de n'avoir qu'à écrire une implémentation CompareTo distincte dans le cas où une comparaison plus subtile doit avoir lieu (c'est-à-dire où les deux sont des instances Derived) et pour tous les autres scénarios laisser simplement la résolution de surcharge revenir sur le comparaison suffisante dans Base.CompareTo. Hélas ... :) – Anton

1

IComparable<Base> et IComparable<Derived> sont deux types différents, donc deux méthodes CompareTo dans Derived sont mis en correspondance sur deux emplacements différents. CompareTo appelé par BaseComparer appelle la méthode de IComparable<Base>.Vous pouvez indiquer CompareTo(Base) dans Base comme virtual et le remplacer dans Derived pour obtenir le comportement (partiellement) attendu.

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