CA1036: переопределяйте методы в сравнимых типах
TypeName |
OverrideMethodsOnComparableTypes |
CheckId |
CA1036 |
Категория |
Microsoft.Design |
Критическое изменение |
Не критическое |
Причина
Открытый или защищенный тип реализует интерфейс System.IComparable и не переопределяет Object.Equals или не перегружает характерный для языка оператор равенства, неравенства, большинства или меньшинства. Если тип только наследует реализацию интерфейса, правило не выводит сообщение о нарушении.
Описание правила
Типы, определяющие пользовательский порядок сортировки, реализуют интерфейс IComparable. Метод CompareTo возвращает целочисленное значение, указывающее правильный порядок сортировки для двух экземпляров типа. Это правило определяет типы, задающие порядок сортировки; это подразумевает, что обычное понимание равенства, неравенства, большинства или меньшинства не применяется. При предоставлении реализации IComparable обычно необходимо переопределить Equals для возвращения значений, согласованных с методом CompareTo. При переопределении Equals и кодировании на языке, поддерживающем перегрузки операторов, необходимо также предоставить операторы, согласующиеся с Equals.
Устранение нарушений
Чтобы устранить нарушение данного правила, переопределите Equals. Если используемый язык программирования поддерживает перегрузку операторов, предоставьте следующие операторы.
op_Equality
op_Inequality
op_LessThan
op_GreaterThan
В C# для представления этих операторов используются следующие маркеры: ==, !=, <, and >.
Отключение предупреждений
Если причиной нарушения является отсутствие операторов и язык программирования не поддерживает перегрузку операторов (как в случае с Visual Basic .NET) для данного правила вывод предупреждения можно отключить. Безопасно отключить предупреждения о нарушении данного правила при срабатывании на операторы равенства, кроме op_Equality, если вы определили, что в реализации операторов нет смысла в контексте вашего приложения. Тем не менее, следует всегда закрывать op_Equality и оператор == при переопределении Object.Equals.
Пример
В следующем примере содержится тип, правильно реализующий IComparable. Комментарии кода выявляют методы, удовлетворяющие различным правилам, связанным с Equals и интерфейсом 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);
}
}
}
В следующем приложении тестируется поведение реализации IComparable, представленной ранее.
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);
}
}
}