共用方式為


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

型別名稱

OverrideMethodsOnComparableTypes

CheckId

CA1036

分類

Microsoft.Design

中斷變更

中斷

原因

公用或保護的型別會實作 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);      
       }
    }
}

請參閱

參考

IComparable

Object.Equals

其他資源

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