Share via


CA1036: Åsidosätt metoder för jämförbara typer

Property Värde
Regel-ID CA1036
Rubrik Åsidosätt metoder för jämförbara typer
Kategori Designa
Korrigeringen är icke-bakåtkompatibel Icke-icke-bryta
Aktiverad som standard i .NET 8 Nej

Orsak

En typ implementerar gränssnittet och åsidosätter System.IComparableSystem.Object.Equals inte eller överbelastar inte den språkspecifika operatorn för likhet, ojämlikhet, mindre än eller större än. Regeln rapporterar inte en överträdelse om typen bara ärver en implementering av gränssnittet.

Som standard tittar den här regeln bara på externt synliga typer, men det kan konfigureras.

Regelbeskrivning

Typer som definierar en anpassad sorteringsordning implementerar IComparable gränssnittet. Metoden CompareTo returnerar ett heltalsvärde som anger rätt sorteringsordning för två instanser av typen. Den här regeln identifierar typer som anger en sorteringsordning. Att ange en sorteringsordning innebär att den vanliga innebörden av likhet, ojämlikhet, mindre än och större än inte gäller. När du anger en implementering av IComparablemåste du vanligtvis också åsidosätta Equals så att den returnerar värden som är konsekventa med CompareTo. Om du åsidosätter Equals och kodar på ett språk som stöder överlagring av operatorer bör du även ange operatorer som är konsekventa med Equals.

Så här åtgärdar du överträdelser

Om du vill åtgärda ett brott mot den här regeln åsidosätter du Equals. Om programmeringsspråket stöder överlagring av operatorer anger du följande operatorer:

  • op_Equality
  • op_Inequality
  • op_LessThan
  • op_GreaterThan

I C# är de token som används för att representera dessa operatorer följande:

==
!=
<
>

När du ska ignorera varningar

Det är säkert att ignorera en varning från regeln CA1036 när överträdelsen orsakas av saknade operatorer och programmeringsspråket inte stöder överlagring av operatören, vilket är fallet med Visual Basic. Om du bedömer att implementeringen av operatorerna inte är meningsfull i appkontexten är det också säkert att ignorera en varning från den här regeln när den utlöses på andra likhetsoperatorer än op_Equality. Du bör dock alltid åsidosätta op_Equality och operatorn == om du åsidosätter Object.Equals.

Ignorera en varning

Om du bara vill förhindra en enda överträdelse lägger du till förprocessordirektiv i källfilen för att inaktivera och aktiverar sedan regeln igen.

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

Om du vill inaktivera regeln för en fil, mapp eller ett projekt anger du dess allvarlighetsgrad till none i konfigurationsfilen.

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

Mer information finns i Så här utelämnar du kodanalysvarningar.

Konfigurera kod för analys

Använd följande alternativ för att konfigurera vilka delar av kodbasen som regeln ska köras på.

Du kan konfigurera det här alternativet för bara den här regeln, för alla regler som gäller för eller för alla regler i den här kategorin (design) som den gäller för. Mer information finns i Konfigurationsalternativ för kodkvalitetsregel.

Inkludera specifika API-ytor

Du kan konfigurera vilka delar av kodbasen som ska köras med den här regeln baserat på deras tillgänglighet. Om du till exempel vill ange att regeln endast ska köras mot den icke-offentliga API-ytan lägger du till följande nyckel/värde-par i en .editorconfig-fil i projektet:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Exempel

Följande kod innehåller en typ som implementerar IComparablekorrekt . Kodkommentar identifierar de metoder som uppfyller olika regler som är relaterade till Equals och IComparable gränssnittet.

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

Följande programkod testar beteendet för implementeringen IComparable som visades tidigare.

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

Se även