CA1036: Zastępuj metody na typach porównywalnych
TypeName |
OverrideMethodsOnComparableTypes |
CheckId |
CA1036 |
Kategoria |
Microsoft.Design |
Zmiana kluczowa |
Niekluczowa |
Przyczyna
Typy public lub protected implementują interfejs IComparable i nie zastępują metody Object.Equals lub nie przeciążają operatorów równości, nierówności, mniejszy niż, większy niż specyficznych dla języka.Reguła nie zgłasza naruszenia, jeśli typ dziedziczy tylko implementację interfejsu.
Opis reguły
Typ, który definiuje własny porządek sortowania, implementuje interfejs IComparable.Metoda CompareTo zwraca wartość całkowitą, która wskazuje właściwy porządek sortowania dla dwóch wystąpień tego typu.Ta reguła identyfikuje typy, które określają porządek sortowania; oznacza to, że normalne znaczenie równości nierówności, mniejszości i większości nie ma już zastosowania.Po wprowadzeniu implementacji IComparable, należy również zastąpić metodę Equals, tak aby zwracała wartości, które są zgodne z CompareTo.Jeżeli zastąpisz metodę Equals i kodujesz w języku obsługującym przeciążenia operatora, należy również dostarczyć operatory, które są zgodne z Equals.
Jak naprawić naruszenia
Aby naprawić naruszenie tej zasady, należy zastąpić Equals.Jeśli język programowania obsługuje przeciążanie operatora, należy dostarczyć następujące operatory:
op_Equality
op_Inequality
op_LessThan
op_GreaterThan
W języku C#, tokeny, które są używane do reprezentowania tych operatorów, są następujące: ==, !=, <, i >.
Kiedy pominąć ostrzeżenia
Bezpiecznie jest pominąć ostrzeżenia od tej reguły, gdy naruszenie jest spowodowane brakującymi operatorami a język programowania nie wspiera przeciążania operatora, tak jak w przypadku Visual Basic .NET.Jest również bezpieczne pominąć ostrzeżenie od tej reguły, gdy uruchamiane jest na operatorach równości, innych niż op_Equality, jeśli okaże się, że implementacja operatorów nie ma sensu w kontekście aplikacji.Jednak należy zawsze zastąpić operator op_Equality i ==, jeśli zastępujesz metodę Object.Equals.
Przykład
Poniższy przykład zawiera typ, który implementuje poprawnie IComparable.Komentarze kodu identyfikują metody, które spełniają różne reguły, które są powiązane z Equals i interfejsem 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);
}
}
}
Poniższa aplikacja testuje zachowanie implementacji IComparable pokazanej wcześniej.
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);
}
}
}
Zobacz też
Informacje
Inne zasoby
Guidelines for Implementing Equals and the Equality Operator (==)