Compartir a través de


CA1036: Reemplazar métodos en tipos comparables

Nombre de tipo

OverrideMethodsOnComparableTypes

Identificador de comprobación

CA1036

Categoría

Microsoft.Design

Cambio problemático

Poco problemático

Motivo

Un tipo público o protegido implementa la interfaz System.IComparable y no reemplaza Object.Equals ni sobrecarga el operador específico del leguaje por uno de igualdad, desigualdad o mayor que él.La regla no informa de una infracción si el tipo hereda únicamente una implementación de la interfaz.

Descripción de la regla

Los tipos que definen un criterio de ordenación personalizado implementan la interfaz IComparable.El método CompareTo devuelve un valor entero que indica el criterio de ordenación correcto para dos instancias del tipo.Esta regla identifica los tipos que establecen el criterio de ordenación; esto implica que no se aplique el criterio ordinario de igualdad, desigualdad, menor o mayor que.Cuando proporcione una implementación de IComparable, normalmente también debe reemplazar Equals de modo que devuelva los valores coherentes con CompareTo.Si reemplaza Equals y está codificando en un lenguaje que admite las sobrecargas de operador, también debería proporcionar operadores coherentes con Equals.

Cómo corregir infracciones

Para corregir una infracción de esta regla, reemplace Equals.Si su lenguaje de programación admite la sobrecarga de operadores, proporcione los operadores siguientes:

  • op_Equality

  • op_Inequality

  • op_LessThan

  • op_GreaterThan

En C#, los tokens que se utilizan para representar estos operadores son los siguientes: ==, !=, < y >.

Cuándo suprimir advertencias

Es seguro suprimir una advertencia de esta regla cuando la causan los operadores que faltan y el lenguaje de programación no admite la sobrecarga de operadores, como es el caso de Visual Basic .NET.También es seguro suprimir una advertencia de esta regla cuando se desencadena en operadores de igualdad distintos de op_Equality si determina que no tiene sentido implementar los operadores en su contexto de aplicación.Sin embargo, siempre debe invalidar op_Equality y el operador == si invalida Object.Equals.

Ejemplo

El ejemplo siguiente contiene un tipo que implementa IComparable correctamente.‎Los comentarios de código identifican los métodos que cumplen las distintas reglas relacionadas con Equals y la interfaz 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);
        }
    }
}

La aplicación siguiente prueba el comportamiento de la implementación IComparable mostrado anteriormente.

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

Vea también

Referencia

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

System.IComparable

Object.Equals