共用方式為


CA1036:必須在 Comparable 型別中覆寫方法

型別名稱

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# 中,用於代表這些運算子的語彙基元如下所示:==、!=、< 和 >。

隱藏警告的時機

在 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