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

屬性
規則識別碼 CA1036
標題 必須在 Comparable 類型中覆寫方法
類別 設計
修正程式是中斷或非中斷 不中斷
預設在 .NET 8 中啟用 No

原因

類型會實作 System.IComparable 介面,且不會覆寫 System.Object.Equals 或未多載語言特定運算子,以取得相等、不相等、小於或大於。 如果型別只繼承介面的實作,規則不會報告違規。

根據預設,此規則只會查看外部可見的類型,但這是可設定

檔案描述

定義自訂排序次序的類型會實作 IComparable 介面。 方法 CompareTo 會傳回整數值,指出型別兩個實例的正確排序次序。 此規則會識別設定排序次序的類型。 設定排序次序表示相等、不相等、小於和大於的一般意義不適用。 當您提供 的 IComparable 實作時,通常也必須覆寫 Equals ,使其傳回與 CompareTo 一致的值。 如果您以支援運算子多載的語言覆寫 Equals 和撰寫程式碼,則也應該提供與 Equals 一致的運算子。

如何修正違規

若要修正此規則的違規,請覆寫 Equals 。 如果您的程式設計語言支援運算子多載,請提供下列運算子:

  • op_Equality
  • op_Inequality
  • op_LessThan
  • op_GreaterThan

在 C# 中,用來表示這些運算子的權杖如下所示:

==
!=
<
>

隱藏警告的時機

當違規是由遺漏運算子所造成,且您的程式設計語言不支援運算子多載時,隱藏來自規則 CA1036 的警告,就像 Visual Basic 的情況一樣。 如果您判斷實作運算子在應用程式內容中沒有意義,在引發非op_Equality的等號運算子時,隱藏此規則的警告也是安全的。 不過,如果您覆 Object.Equals 寫 ,您應該一律覆寫 op_Equality 和 == 運算子。

隱藏警告

如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。

#pragma warning disable CA1036
// The code that's violating the rule is on this line.
#pragma warning restore CA1036

若要停用檔案、資料夾或專案的規則,請在組態檔 中將其嚴重性設定為 。 none

[*.{cs,vb}]
dotnet_diagnostic.CA1036.severity = none

如需詳細資訊,請參閱 如何隱藏程式碼分析警告

設定程式碼以分析

使用下列選項來設定程式碼基底要執行此規則的部分。

您可以只針對此規則、針對它套用的所有規則,或針對套用至此類別的所有規則, 或針對它套用的所有規則,設定此選項。 如需詳細資訊,請參閱 程式碼品質規則組態選項

包含特定 API 介面

您可以根據程式碼基底的存取範圍,設定要執行此規則的部分。 例如,若要指定規則只應該針對非公用 API 介面執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:

dotnet_code_quality.CAXXXX.api_surface = private, internal

範例

下列程式碼包含可正確實作 IComparable 的型別。 程式碼批註會識別滿足與 EqualsIComparable 介面相關之各種規則的方法。

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

        Rating = v;
    }

    public int CompareTo(object? obj)
    {
        if (obj == null)
        {
            return 1;
        }

        if (obj is RatingInformation other)
        {
            return CompareTo(other);
        }

        throw new ArgumentException("A RatingInformation object is required for comparison.", "obj");
    }

    public int CompareTo(RatingInformation? other)
    {
        if (other is 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 (left is null)
        {
            return -1;
        }
        return left.CompareTo(right);
    }

    // Omitting Equals violates rule: OverrideMethodsOnComparableTypes.
    public override bool Equals(object? obj)
    {
        if (obj is RatingInformation other)
        {
            return this.CompareTo(other) == 0;
        }

        return false;
    }

    // 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 (left is null)
        {
            return right is 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 的行為。

public class Test
{
    public static void Main1036(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);
    }
}

另請參閱