Partager via


CA1036 : Substituer les méthodes sur les types Comparable

TypeName

OverrideMethodsOnComparableTypes

CheckId

CA1036

Catégorie

Microsoft.CSharp

Modification avec rupture

Modification sans rupture

Cause

Un type public ou protégé implémente l'interface System.IComparable et ne substitue pas Object.Equals, ni ne surcharge l'opérateur égal à, différent de, inférieur à ou supérieur à propre au langage. La règle ne rapporte pas d'infraction si le type hérite seulement d'une implémentation de l'interface.

Description de la règle

Les types qui définissent un ordre de tri personnalisé implémentent l'interface IComparable. La méthode CompareTo retourne une valeur entière qui indique l'ordre de tri approprié pour deux instances du type. Cette règle identifie des types qui définissent un ordre de tri, en impliquant que la signification ordinaire des opérations égal à, différent de, supérieur à et inférieur à ne s'applique pas. Lorsque vous fournissez une implémentation de IComparable, vous devez généralement substituer aussi Equals afin qu'il retourne des valeurs cohérentes avec CompareTo. Si vous substituez Equals et codez dans un langage qui prend en charge les surcharges d'opérateur, vous devez également fournir des opérateurs cohérents avec Equals.

Comment corriger les violations

Pour corriger une violation de cette règle, substituez Equals. Si votre langage de programmation prend en charge la surcharge d'opérateur, fournissez les opérateurs suivants :

  • op_Equality

  • op_Inequality

  • op_LessThan

  • op_GreaterThan

En C#, les jetons utilisés pour représenter ces opérateurs sont les suivants : ==, !=, <, et >.

Quand supprimer les avertissements

Il est possible de supprimer sans risque un avertissement de cette règle lorsque la violation est provoquée par des opérateurs manquants et lorsque votre langage de programmation ne prend pas en charge la surcharge d'opérateur, comme c'est le cas avec Visual Basic .NET. Par mesure de sécurité, il est également recommandé de supprimer un avertissement de cette règle quand elle se déclenche sur des opérateurs d'égalité autres que op_Equality si vous considérez qu'il est inutile d'implémenter les opérateurs dans votre contexte d'application. Cependant, vous devez toujours vérifier op_Equality et l'opérateur == si vous remplacez Object.Equals.

Exemple

L'exemple suivant contient un type qui implémente correctement IComparable. Les commentaires de code identifient les méthodes qui satisfont différentes règles en rapport avec Equals et l'interface IComparable.

using System;
using System.Globalization;

namespace DesignLibrary
{
    // Valid ratings are between A and C.
    // A is the highest rating; it is greater than any other valid rating.
    // C is the lowest rating; it is less than any other valid rating.

    public class RatingInformation : IComparable, IComparable<RatingInformation>
    {
        public string Rating
        {
            get;
            private set;
        }

        public RatingInformation(string rating)
        {
            if (rating == null)
            {
                throw new ArgumentNullException("rating");
            }
            string v = rating.ToUpper(CultureInfo.InvariantCulture);
            if (v.Length != 1 || string.Compare(v, "C", StringComparison.Ordinal) > 0 || string.Compare(v, "A", StringComparison.Ordinal) < 0)
            {
                throw new ArgumentException("Invalid rating value was specified.", "rating");
            }
            this.Rating = v;
        }

        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                return 1;
            }
            RatingInformation other = obj as RatingInformation; // avoid double casting
            if (other == null)
            {
                throw new ArgumentException("A RatingInformation object is required for comparison.", "obj");
            }
            return this.CompareTo(other);
        }

        public int CompareTo(RatingInformation other)
        {
            if (object.ReferenceEquals(other, null))
            {
                return 1;
            }
            // Ratings compare opposite to normal string order, 
            // so reverse the value returned by String.CompareTo.
            return -string.Compare(this.Rating, other.Rating, StringComparison.OrdinalIgnoreCase);
        }

        public static int Compare(RatingInformation left, RatingInformation right)
        {
            if (object.ReferenceEquals(left, right))
            {
                return 0;
            }
            if (object.ReferenceEquals(left, null))
            {
                return -1;
            }
            return left.CompareTo(right);
        }

        // Omitting Equals violates rule: OverrideMethodsOnComparableTypes.
        public override bool Equals(object obj)
        {
            RatingInformation other = obj as RatingInformation; //avoid double casting
            if (object.ReferenceEquals(other, null))
            {
                return false;
            }
            return this.CompareTo(other) == 0;
        }

        // Omitting getHashCode violates rule: OverrideGetHashCodeOnOverridingEquals.
        public override int GetHashCode()
        {
            char[] c = this.Rating.ToCharArray();
            return (int)c[0];
        }

        // Omitting any of the following operator overloads 
        // violates rule: OverrideMethodsOnComparableTypes.
        public static bool operator ==(RatingInformation left, RatingInformation right)
        {
            if (object.ReferenceEquals(left, null))
            {
                return object.ReferenceEquals(right, null);
            }
            return left.Equals(right);
        }
        public static bool operator !=(RatingInformation left, RatingInformation right)
        {
            return !(left == right);
        }
        public static bool operator <(RatingInformation left, RatingInformation right)
        {
            return (Compare(left, right) < 0);
        }
        public static bool operator >(RatingInformation left, RatingInformation right)
        {
            return (Compare(left, right) > 0);
        }
    }
}

L'application suivante teste le comportement de l'implémentation IComparable présentée précédemment.

using System;

namespace DesignLibrary
{
    public class Test
    {
       public static void Main(string [] args)
       {
          if (args.Length < 2)
          {
             Console.WriteLine ("usage - TestRatings  string 1 string2");
             return;
          }
          RatingInformation r1 = new RatingInformation(args[0]) ;
          RatingInformation r2 = new RatingInformation( args[1]);
          string answer;

          if (r1.CompareTo(r2) > 0)
             answer = "greater than";
          else if (r1.CompareTo(r2) < 0)
             answer = "less than";
          else
             answer = "equal to";

          Console.WriteLine("{0} is {1} {2}", r1.Rating, answer, r2.Rating);      
       }
    }
}

Voir aussi

Référence

Instructions relatives à l'implémentation de Equals et de l'opérateur d'égalité (==)

System.IComparable

Object.Equals