Question

Devrais-je mettre en œuvre à la fois IComparable et le IComparable<T> générique? Y a-t-il des limites si je ne mettre en œuvre l'un d'entre eux?

Était-ce utile?

La solution

Oui, vous devez mettre en œuvre à la fois.

Si vous implémentez un, tout code qui dépend de l'autre échouera.

Il y a beaucoup de code qui utilise soit IComparable ou IComparable<T> mais pas les deux, de sorte que la mise en œuvre à la fois assurer votre code fonctionnera avec ce code.

Autres conseils

Oded est juste que vous devez mettre en œuvre à la fois parce qu'il ya des collections et d'autres classes qui comptent sur une seule des implémentations.

Mais il y a un truc là-bas: IComparable ne devrait pas lancer des exceptions, alors que IComparable devrait. Lors de la mise en œuvre IComparable vous êtes chargé de veiller à ce que tous les cas de T peuvent être comparés les uns les autres. Cela inclut null, ainsi (null traiter comme plus petit que tous les cas non nuls de T et vous serez très bien).

Cependant, IComparable générale accepte System.Object et vous ne pouvez pas garantir que tous les objets imaginables serait comparable contre les cas de T. Par conséquent, si vous obtenez une instance non-T est passé à IComparable, il suffit de jeter le System.ArgumentException. Dans le cas contraire, acheminer l'appel à la IComparable mise en œuvre.

Voici l'exemple:

public class Piano : IComparable<Piano>, IComparable
{
    public int CompareTo(Piano other) { ... }
    ...
    public int CompareTo(object obj)
    {

        if (obj != null && !(obj is Piano))
            throw new ArgumentException("Object must be of type Piano.");

        return CompareTo(obj as Piano);

    }
}

Cet exemple fait partie d'un article beaucoup plus long qui contient une analyse approfondie des effets secondaires que vous devez prendre soin de la mise en œuvre IComparable : Comment mettre en œuvre IComparable Interface dans la base et les classes dérivées

Alors que IEquatable ne devrait généralement pas être mis en œuvre par les classes non scellées, étant donné que cette dérivation jouait curieusement avec l'héritage à moins que la mise en œuvre appelle simplement Object.Equals (auquel cas il serait inutile), la situation contraire se pose avec le générique IComparable . La sémantique pour Object.Equals et IEquatable impliquent que chaque fois que IEquatable est défini, son comportement doit refléter celle de Object.Equals (en plus d'être plus rapide et peut-être d'éviter la boxe). Deux objets de type DerivedFoo qui sont considérées comme égales quand considéré comme le type DerivedFoo devrait également être égaux quand considérés comme des objets de type Foo, et vice-versa. D'autre part, il est tout à fait possible que deux objets de type DerivedFoo ce rang quand considéré comme inégale de type DerivedFoo devraient classer également quand considéré comme le type Foo. La seule façon d'assurer est d'utiliser IComparable .

Supposons, par exemple, une a une SchedulerEvent de classe qui contient des champs ScheduledTime (de type DateTime) et ScheduledAction (de type MethodInvoker). La classe comprend les sous-types SchedulerEventWithMessage (ce qui ajoute un champ de message de type chaîne) et SchedulerEventWithGong (ce qui ajoute un champ GongVolume de type double). La classe SchedulerEvent a un ordre naturel, par ScheduledTime, mais il est tout à fait possible pour les événements qui ne sont pas ordonnés par rapport à l'autre pour être inégale. Les classes SchedulerEventWithMessage et SchedulerEventWithGong ont aussi ordonnancements naturels entre eux, mais pas par rapport aux éléments de SchedulerEvent de classe.

Supposons que l'on a deux événements SchedulerEventWithMessage X et Y prévus pour en même temps, mais X.Message est « Aardvark » et Y.Message est « zymurgy ». ((IComparable ) X) .CompareTo (Y) doit signaler zéro (puisque les événements ont des temps égaux) mais ((IComparable ) X) .CompareTo (Y) renvoyer un nombre négatif (depuis "Aardvark" avant "zymurgy"). Si la classe ne se comportait pas de cette façon, il serait difficile, voire impossible, d'ordonner systématiquement une liste qui contient un mélange d'objets SchedulerEventWithMessage et SchedulerEventWithGong.

Soit dit en passant, on peut dire que ce serait utile d'avoir la sémantique de IEquatable objets comparer seulement la base des éléments de type T, de sorte que par exemple, IEquatable vérifierait ScheduledTime et ScheduledAction pour l'égalité, mais même lorsqu'elle est appliquée à un SchedulerEventWithMessage ou SchedulerEventWithGong ne vérifierait pas les propriétés des messages ou GongVolume. En effet, ceux qui seraient utiles pour la sémantique d'un IEquatable méthode, et je préfère opter pour telle sémantique, mais pour un problème: comparer .Default.GetHashCode (T) appelle toujours la même fonction Object.GetHashCode () quel que soit de type T. Cela limite considérablement la capacité de IEquatable pour modifier son comportement avec différents types T.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top