Condividi tramite


CA1036: Eseguire l'override di metodi su tipi confrontabili

TypeName

OverrideMethodsOnComparableTypes

CheckId

CA1036

Category

Microsoft.Design

Breaking Change

Non sostanziale

Causa

Un tipo pubblico o protetto implementa l'interfaccia System.IComparable e non esegue l'override di Object.Equals né dell'operatore di uguaglianza, disuguaglianza, minore di o maggiore di specifico del linguaggio.La regola non segnala una violazione se il tipo eredita solo un'implementazione dell'interfaccia.

Descrizione della regola

I tipi che definiscono un criterio di ordinamento personalizzato implementano l'interfaccia IComparable.Il metodo CompareTo restituisce un Integer che indica il criterio di ordinamento corretto per due istanze del tipo.Questa regola identifica i tipi che impostano un criterio di ordinamento, implicando che il significato ordinario di uguaglianza, disuguaglianza, minore di e maggiore di non è applicabile.Quando si fornisce un'implementazione di IComparable, è necessario eseguire anche l'override di Equals in modo che restituisca valori coerenti con CompareTo.Se si esegue l'override di Equals e il linguaggio in uso supporta gli overload degli operatori, è inoltre necessario fornire operatori coerenti con Equals.

Come correggere le violazioni

Per correggere una violazione di questa regola, eseguire l'override di Equals.Se il linguaggio di programmazione in uso supporta l'overload degli operatori, fornire gli operatori riportati di seguito:

  • op_Equality

  • op_Inequality

  • op_LessThan

  • op_GreaterThan

In C#, i token utilizzati per rappresentare questi operatori sono i seguenti: ==, !=, < e >.

Esclusione di avvisi

L'esclusione di un avviso da questa regola è sicura se la violazione è causata da operatori mancanti e il linguaggio di programmazione non supporta l'overload degli operatori, come nel caso di Visual Basic .NET.L'esclusione di un avviso da questa regola quando genera in operatori diversi da op_Equality è sicura anche se viene determinato che l'implementazione degli operatori non ha senso nel contesto di applicazione.Tuttavia, se si esegue l'override di Object.Equals, è sempre necessario eseguire l'override di op_Equality e dell'operatore ==.

Esempio

Nell'esempio riportato di seguito è contenuto un tipo che implementa correttamente IComparable.I commenti al codice identificano i metodi che soddisfano varie regole correlate a Equals e all'interfaccia 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);
        }
    }
}

Nell'applicazione riportata di seguito viene verificato il comportamento dell'implementazione IComparable illustrata in precedenza.

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

Vedere anche

Riferimenti

Guidelines for Implementing Equals and the Equality Operator (==)

System.IComparable

Object.Equals