CA1036: 비교 가능한 형식에 메서드를 재정의하십시오.
속성 | 값 |
---|---|
규칙 ID | CA1036 |
제목 | 비교 가능한 형식에 메서드를 재정의하세요. |
범주 | 디자인 |
수정 사항이 주요 변경인지 여부 | 주요 변경 아님 |
.NET 9에서 기본적으로 사용 | 아니요 |
원인
형식은 System.IComparable 인터페이스를 구현하며 System.Object.Equals를 재정의하지 않고 같음, 같지 않음, 보다 작음 또는 보다 큼에 대한 언어별 연산자를 오버로드하지 않습니다. 형식이 인터페이스의 구현만 상속하는 경우에는 규칙이 위반을 보고하지 않습니다.
기본적으로 이 규칙은 외부에 표시되는 형식만 확인하지만 이는 구성 가능합니다.
규칙 설명
사용자 지정 정렬 순서를 정의하는 형식은 IComparable 인터페이스를 구현합니다. CompareTo 메서드는 형식의 두 인스턴스의 올바른 정렬 순서를 나타내는 정수 값을 반환합니다. 이 규칙은 정렬 순서를 설정하는 형식을 식별합니다. 정렬 순서를 설정하는 것은 같음, 같지 않음, 보다 작음, 보다 큼의 일반적인 의미가 적용되지 않는다는 것을 의미합니다. IComparable의 구현을 제공하는 경우에는 일반적으로 CompareTo와 일치하는 값을 반환하도록 Equals를 재정의해야 합니다. 연산자 오버로드를 지원하는 언어에서 Equals를 재정의하고 코딩하는 경우에는 Equals와 일치하는 연산자도 제공해야 합니다.
위반 문제를 해결하는 방법
이 규칙 위반 문제를 해결하려면 Equals를 재정의합니다. 프로그래밍 언어가 연산자 오버로드를 지원하는 경우 다음 연산자를 제공합니다.
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
경고를 표시하지 않는 경우
누락된 연산자에 의해 위반이 발생하고 프로그래밍 언어가 연산자 오버로드를 지원하지 않는 경우 규칙 CA1036의 경고를 표시하지 않아도 됩니다. 연산자 구현이 앱 컨텍스트에서 의미가 없다고 판단하는 경우 이 규칙이 아닌 op_Equality
같음 연산자에서 실행되는 경우에도 이 규칙의 경고를 표시하지 않는 것이 안전합니다. 그러나 재정의하는 경우 항상 op_Equality
재정의하고 연산자를 재정Object.Equals의 ==
해야 합니다.
경고 표시 안 함
단일 위반만 표시하지 않으려면 원본 파일에 전처리기 지시문을 추가하여 규칙을 사용하지 않도록 설정한 후 다시 사용하도록 설정합니다.
#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를 올바르게 구현하는 형식이 포함되어 있습니다. 코드 주석은 Equals 및 IComparable 인터페이스와 관련된 다양한 규칙을 충족하는 메서드를 식별합니다.
// 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
다음 애플리케이션 코드는 앞에서 설명한 IComparable 구현의 동작을 테스트합니다.
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("{0} is {1} {2}", r1.Rating, 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
참고 항목
.NET