다음을 통해 공유


CA1036: 비교 가능한 형식에 메서드를 재정의하십시오.

TypeName

OverrideMethodsOnComparableTypes

CheckId

CA1036

범주

Microsoft.Design

변경 수준

주요 변경 아님

원인

public 또는 protected 형식에서 System.IComparable 인터페이스를 구현하고, Object.Equals를 재정의하지 않거나 같음, 같지 않음, 보다 작음 또는 보다 큼에 대한 언어별 연산자를 오버로드하지 않습니다. 이 규칙에서는 형식이 인터페이스의 구현만 상속하는 경우 위반을 보고하지 않습니다.

규칙 설명

사용자 지정 정렬 순서를 정의하는 형식은 IComparable 인터페이스를 구현합니다. CompareTo 메서드는 해당 형식의 두 인스턴스에 대한 적절한 정렬 순서를 나타내는 정수 값을 반환합니다. 이 규칙에서는 정렬 순서를 설정하는 형식을 식별하며 이것은 같음, 같지 않음, 보다 작음 및 보다 큼의 일반적인 의미가 적용되지 않는다는 것을 나타냅니다. IComparable의 구현을 제공하는 경우 Equals도 재정의하여 CompareTo와 일관된 값을 반환하도록 해야 합니다. Equals를 재정의하고 연산자 오버로드를 지원하는 언어로 코딩하는 경우 Equals와 일관성 있는 연산자도 제공해야 합니다.

위반 문제를 해결하는 방법

이 규칙 위반 문제를 해결하려면 Equals를 재정의합니다. 사용하는 프로그래밍 언어에서 연산자 오버로드를 지원하는 경우 다음 연산자를 제공합니다.

  • op_Equality

  • op_Inequality

  • op_LessThan

  • op_GreaterThan

C#에서 이들 연산자를 나타내는 데 사용되는 토큰은 ==, !=, < 및 >입니다.

경고를 표시하지 않는 경우

Visual Basic .NET에서와 마찬가지로 연산자가 없어서 위반이 발생하였고 프로그래밍 언어에서 연산자 오버로드를 지원하지 않는 경우에는 이 규칙에서 경고를 표시하지 않아도 안전합니다. 연산자 구현이 응용 프로그램 컨텍스트에서 의미가 없다고 판단되는 경우 op_Equality 이외의 같음 연산자에서 발생할 때 이 규칙에서 경고를 표시하지 않는 것도 안전합니다. 그러나 Object.Equals를 재정의하는 경우 항상 op_Equality 및 == 연산자 위에 있어야 합니다.

예제

다음 예제에는 IComparable을 올바르게 구현하는 형식이 포함되어 있습니다. 코드 주석을 통해 EqualsIComparable 인터페이스에 관련된 다양한 규칙을 충족하는 메서드를 식별할 수 있습니다.

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