次の方法で共有


CA1036: 比較可能な型でメソッドをオーバーライドします

TypeName

OverrideMethodsOnComparableTypes

CheckId

CA1036

[カテゴリ]

Microsoft.Design

互換性に影響する変更点

なし

原因

パブリック型またはプロテクト型で System.IComparable インターフェイスが実装されています。これによって Object.Equals はオーバーライドされません。また、"等しい"、"等しくない"、"未満"、"より大きい" を示す言語固有の演算子はオーバーロードされません。型でインターフェイスの実装のみを継承している場合、この規則違反はレポートされません。

規則の説明

カスタムの並べ替え順序を定義する型では、IComparable インターフェイスを実装します。CompareTo メソッドは、その型の 2 つのインスタンスについて、適切な並べ替え順序を示す整数値を返します。この規則では、並べ替え順序を設定する型を識別します。つまり、一般的な意味の "等しい"、"等しくない"、"未満"、"より大きい" は適用されません。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);      
       }
    }
}

参照

関連項目

Guidelines for Implementing Equals and the Equality Operator (==)

System.IComparable

Object.Equals