Поделиться через


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

См. также

Ссылки

Правила реализации метода Equals и оператора равенства (==)

System.IComparable

Object.Equals