Bagikan melalui


CA1036: Ganti metode pada jenis yang sebanding

Properti Nilai
ID Aturan CA1036
Judul Ambil alih metode pada jenis yang sebanding
Golongan Desain
Perbaikan bersifat disruptif atau non-disruptif Non-disruptif
Diaktifkan secara default di .NET 9 No

Penyebab

Jenis mengimplementasikan System.IComparable antarmuka dan tidak mengambil alih System.Object.Equals atau tidak membebani operator khusus bahasa untuk kesetaraan, ketidaksetaraan, kurang dari, atau lebih besar dari. Aturan tidak melaporkan pelanggaran jika jenis hanya mewarisi implementasi antarmuka.

Secara default, aturan ini hanya melihat jenis yang terlihat secara eksternal, tetapi ini dapat dikonfigurasi.

Deskripsi aturan

Jenis yang menentukan urutan pengurutan IComparable kustom mengimplementasikan antarmuka. Metode mengembalikan CompareTo nilai bilangan bulat yang menunjukkan urutan pengurutan yang benar untuk dua instans jenis. Aturan ini mengidentifikasi jenis yang mengatur urutan pengurutan. Mengatur urutan pengurutan menyiratkan bahwa arti biasa dari kesetaraan, ketidaksetaraan, kurang dari, dan lebih besar dari yang tidak berlaku. Ketika Anda memberikan implementasi IComparable, Anda biasanya juga harus mengambil alih Equals sehingga mengembalikan nilai yang konsisten dengan CompareTo. Jika Anda mengambil Equals alih dan mengodekan dalam bahasa yang mendukung kelebihan beban operator, Anda juga harus menyediakan operator yang konsisten dengan Equals.

Cara memperbaiki pelanggaran

Untuk memperbaiki pelanggaran aturan ini, ambil alih Equals. Jika bahasa pemrograman Anda mendukung kelebihan beban operator, berikan operator berikut:

  • op_Equality
  • op_Inequality
  • op_LessThan
  • op_GreaterThan
// In C#, implement these operators.
public static bool operator ==(SampleClass? one, SampleClass? other) { }
public static bool operator !=(SampleClass? one, SampleClass? other) { }
public static bool operator <(SampleClass? one, SampleClass? other) { }
public static bool operator >(SampleClass? one, SampleClass? other) { }
' In Visual Basic, implement these operators.

Public Shared Operator =(one As SampleClass, other As SampleClass) As Boolean
    ...
End Operator

Public Shared Operator <>(one As SampleClass, other As SampleClass) As Boolean
    ...
End Operator

Public Shared Operator <(one As SampleClass, other As SampleClass) As Boolean
    ...
End Operator

Public Shared Operator >(one As SampleClass, other As SampleClass) As Boolean
    ...
End Operator

Kapan harus menekan peringatan

Aman untuk menekan peringatan dari aturan CA1036 ketika pelanggaran disebabkan oleh operator yang hilang dan bahasa pemrograman Anda tidak mendukung kelebihan beban operator. Jika Anda menentukan bahwa menerapkan operator tidak masuk akal dalam konteks aplikasi Anda, juga aman untuk menekan peringatan dari aturan ini ketika diaktifkan pada operator kesetaraan selain op_Equality. Namun, Anda harus selalu mengambil alih op_Equality dan == operator jika Anda mengambil alih Object.Equals.

Menyembunyikan peringatan

Jika Anda hanya ingin menyembunyikan satu pelanggaran, tambahkan arahan praprosedur ke file sumber Anda untuk dinonaktifkan lalu aktifkan kembali aturannya.

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

Untuk menonaktifkan aturan untuk file, folder, atau proyek, atur tingkat keparahannya ke none dalam file konfigurasi.

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

Untuk informasi selengkapnya, lihat Cara menyembunyikan peringatan analisis kode.

Mengonfigurasi kode yang akan dianalisis

Gunakan opsi berikut untuk mengonfigurasi bagian mana dari codebase Anda yang akan menjalankan aturan ini.

Anda dapat mengonfigurasi opsi ini hanya untuk aturan ini, untuk semua aturan yang berlaku untuknya, atau untuk semua aturan dalam kategori ini (Desain) yang berlaku untuk aturan ini. Untuk informasi selengkapnya, lihat Opsi konfigurasi aturan kualitas kode.

Menyertakan permukaan API tertentu

Anda dapat mengonfigurasi bagian basis kode mana yang akan dijalankan aturan ini, berdasarkan aksesibilitasnya, dengan mengatur opsi api_surface. Misalnya, untuk menentukan bahwa aturan hanya boleh dijalankan pada permukaan API non-publik, tambahkan pasangan kunci-nilai berikut ke file .editorconfig di proyek Anda:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Nota

Ganti bagian XXXXCAXXXX dengan ID aturan yang berlaku.

Contoh

Kode berikut berisi jenis yang mengimplementasikan IComparabledengan benar . Komentar kode mengidentifikasi metode yang memenuhi berbagai aturan yang terkait dengan Equals dan IComparable antarmuka.

// 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)
    {
        ArgumentNullException.ThrowIfNull(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.", nameof(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.", nameof(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(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 CompareTo(other) == 0;
        }

        return false;
    }

    // Omitting getHashCode violates rule: OverrideGetHashCodeOnOverridingEquals.
    public override int GetHashCode()
    {
        char[] c = 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);
    }
}
Imports System.Globalization

Public Class RatingInformation
    Implements IComparable
    Implements IComparable(Of RatingInformation)

    Public Sub New(rating As String)
        ArgumentNullException.ThrowIfNull(rating)

        Dim v As String = rating.ToUpper(CultureInfo.InvariantCulture)
        If (v.Length <> 1 Or
            String.Compare(v, "C", StringComparison.Ordinal) > 0 Or
            String.Compare(v, "A", StringComparison.Ordinal) < 0) Then
            Throw New ArgumentException("Invalid rating value was specified.", NameOf(rating))
        End If

        Me.Rating = v
    End Sub

    Public ReadOnly Property Rating As String

    Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
        If (obj Is Nothing) Then Return 1
        If (TypeOf obj IsNot RatingInformation) Then Return 0
        Dim other As RatingInformation = DirectCast(obj, RatingInformation)
        Return CompareTo(other)
    End Function

    Public Function CompareTo(other As RatingInformation) As Integer Implements IComparable(Of RatingInformation).CompareTo
        If (other Is Nothing) Then Return 1
        ' Ratings compare opposite To normal String order,
        ' so reverse the value returned by String.CompareTo.
        Return -String.Compare(Rating, other.Rating, StringComparison.OrdinalIgnoreCase)
    End Function

    Public Shared Operator =(one As RatingInformation, other As RatingInformation) As Boolean
        If (one Is Nothing) Then Return (other Is Nothing)
        If (other Is Nothing) Then Return False
        Return (one.Rating = other.Rating)
    End Operator

    Public Shared Operator <>(one As RatingInformation, other As RatingInformation) As Boolean
        If (one Is Nothing) Then Return (other IsNot Nothing)
        If (other Is Nothing) Then Return True
        Return (one.Rating <> other.Rating)
    End Operator

    Public Shared Operator <(one As RatingInformation, other As RatingInformation) As Boolean
        If (one Is Nothing) Then Return (other IsNot Nothing)
        If (other Is Nothing) Then Return False
        Return (one.Rating < other.Rating)
    End Operator

    Public Shared Operator >(one As RatingInformation, other As RatingInformation) As Boolean
        If (one Is Nothing) Then Return False
        If (other Is Nothing) Then Return True
        Return (one.Rating > other.Rating)
    End Operator

    Public Overrides Function Equals(obj As Object) As Boolean
        If ReferenceEquals(Me, obj) Then
            Return True
        End If

        If obj Is Nothing Then
            Return False
        End If

        Throw New NotImplementedException()
    End Function

    Public Overrides Function GetHashCode() As Integer
        Throw New NotImplementedException()
    End Function
End Class

Kode aplikasi berikut menguji perilaku IComparable implementasi yang ditunjukkan sebelumnya.

public class TestCompare
{
    public static void Main1036(params string[] args)
    {
        if (args.Length < 2)
        {
            return;
        }
        RatingInformation r1 = new(args[0]);
        RatingInformation r2 = new(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($"{r1.Rating} is {answer} {r2.Rating}");
    }
}
Public Class TestCompare
    Public Shared Sub Main1036(ByVal args As String())
        If (args.Length < 2) Then
            Return
        End If
        Dim r1 As New RatingInformation(args(0))
        Dim r2 As New RatingInformation(args(1))
        Dim answer As String

        If (r1.CompareTo(r2) > 0) Then
            answer = "greater than"
        ElseIf (r1.CompareTo(r2) < 0) Then
            answer = "less than"
        Else
            answer = "equal to"
        End If

        Console.WriteLine("{0} is {1} {2}", r1.Rating, answer, r2.Rating)
    End Sub
End Class

Lihat juga