CA1036: Reemplazar métodos en tipos comparables
TypeName |
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 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
Otros recursos
Guidelines for Implementing Equals and the Equality Operator (==)