CA2224: 같음 연산자를 오버로드할 때 Equals를 재정의하십시오.
항목 | 값 |
---|---|
RuleId | CA2224 |
범주 | Microsoft.Usage |
주요 변경 내용 | 주요 변경 아님 |
원인
public 형식은 같음 연산자를 구현하지만 System.Object.Equals를 재정의하지 않습니다.
규칙 설명
같음 연산자는 구문상 편리하게 Equals 메서드 기능에 액세스하는 방법입니다. 같음 연산자를 구현하는 경우 해당 논리는 Equals의 논리와 동일해야 합니다.
코드가 이 규칙을 위반하는 경우 C# 컴파일러에서 경고가 발생합니다.
위반 문제를 해결하는 방법
이 규칙 위반 문제를 해결하려면 같음 연산자의 구현을 제거하거나 Equals를 재정의하고 두 메서드가 같은 값을 반환해야 합니다. 같음 연산자에서 일관되지 않은 동작을 도입하지 않는 경우 기본 클래스의 Equals메서드를 호출하는 Equals의 구현을 제공하여 위반을 해결할 수 있습니다.
경고를 표시하지 않는 경우
같음 연산자가 Equals의 상속된 구현과 동일한 값을 반환하는 경우에는 이 규칙에서 경고를 표시하지 않아도 됩니다. 이 문서의 예제에는 이 규칙에서 경고를 안전하게 표시하지 않을 수 있는 형식이 포함되어 있습니다.
일치하지 않는 같음 정의 예제
다음 예제에서는 일치하지 않는 같음 정의가 포함된 형식을 보여 줍니다. BadPoint
는 같음 연산자의 사용자 지정 구현을 제공하여 같음의 의미를 변경하지만 동일하게 동작하도록 Equals를 재정의하지 않습니다.
using System;
namespace UsageLibrary
{
public class BadPoint
{
private int x,y, id;
private static int NextId;
static BadPoint()
{
NextId = -1;
}
public BadPoint(int x, int y)
{
this.x = x;
this.y = y;
id = ++(BadPoint.NextId);
}
public override string ToString()
{
return String.Format("([{0}] {1},{2})",id,x,y);
}
public int X {get {return x;}}
public int Y {get {return x;}}
public int Id {get {return id;}}
public override int GetHashCode()
{
return id;
}
// Violates rule: OverrideEqualsOnOverridingOperatorEquals.
// BadPoint redefines the equality operator to ignore the id value.
// This is different from how the inherited implementation of
// System.Object.Equals behaves for value types.
// It is not safe to exclude the violation for this type.
public static bool operator== (BadPoint p1, BadPoint p2)
{
return ((p1.x == p2.x) && (p1.y == p2.y));
}
// The C# compiler and rule OperatorsShouldHaveSymmetricalOverloads require this.
public static bool operator!= (BadPoint p1, BadPoint p2)
{
return !(p1 == p2);
}
}
}
다음 코드는 BadPoint
의 동작을 테스트합니다.
using System;
namespace UsageLibrary
{
public class TestBadPoint
{
public static void Main()
{
BadPoint a = new BadPoint(1,1);
BadPoint b = new BadPoint(2,2);
BadPoint a1 = a;
BadPoint bcopy = new BadPoint(2,2);
Console.WriteLine("a = {0} and b = {1} are equal? {2}", a, b, a.Equals(b)? "Yes":"No");
Console.WriteLine("a == b ? {0}", a == b ? "Yes":"No");
Console.WriteLine("a1 and a are equal? {0}", a1.Equals(a)? "Yes":"No");
Console.WriteLine("a1 == a ? {0}", a1 == a ? "Yes":"No");
// This test demonstrates the inconsistent behavior of == and Object.Equals.
Console.WriteLine("b and bcopy are equal ? {0}", bcopy.Equals(b)? "Yes":"No");
Console.WriteLine("b == bcopy ? {0}", b == bcopy ? "Yes":"No");
}
}
}
이 예제는 다음과 같은 출력을 생성합니다.
a = ([0] 1,1) and b = ([1] 2,2) are equal? No
a == b ? No
a1 and a are equal? Yes
a1 == a ? Yes
b and bcopy are equal ? No
b == bcopy ? Yes
다음 예제에서는 기술적으로 이 규칙을 위반하지만 일치하지 않는 방식으로 동작하지 않는 형식을 보여 줍니다.
using System;
namespace UsageLibrary
{
public struct GoodPoint
{
private int x,y;
public GoodPoint(int x, int y)
{
this.x = x;
this.y = y;
}
public override string ToString()
{
return String.Format("({0},{1})",x,y);
}
public int X {get {return x;}}
public int Y {get {return x;}}
// Violates rule: OverrideEqualsOnOverridingOperatorEquals,
// but does not change the meaning of equality;
// the violation can be excluded.
public static bool operator== (GoodPoint px, GoodPoint py)
{
return px.Equals(py);
}
// The C# compiler and rule OperatorsShouldHaveSymmetricalOverloads require this.
public static bool operator!= (GoodPoint px, GoodPoint py)
{
return !(px.Equals(py));
}
}
}
다음 코드는 GoodPoint
의 동작을 테스트합니다.
using System;
namespace UsageLibrary
{
public class TestGoodPoint
{
public static void Main()
{
GoodPoint a = new GoodPoint(1,1);
GoodPoint b = new GoodPoint(2,2);
GoodPoint a1 = a;
GoodPoint bcopy = new GoodPoint(2,2);
Console.WriteLine("a = {0} and b = {1} are equal? {2}", a, b, a.Equals(b)? "Yes":"No");
Console.WriteLine("a == b ? {0}", a == b ? "Yes":"No");
Console.WriteLine("a1 and a are equal? {0}", a1.Equals(a)? "Yes":"No");
Console.WriteLine("a1 == a ? {0}", a1 == a ? "Yes":"No");
// This test demonstrates the consistent behavior of == and Object.Equals.
Console.WriteLine("b and bcopy are equal ? {0}", bcopy.Equals(b)? "Yes":"No");
Console.WriteLine("b == bcopy ? {0}", b == bcopy ? "Yes":"No");
}
}
}
이 예제는 다음과 같은 출력을 생성합니다.
a = (1,1) and b = (2,2) are equal? No
a == b ? No
a1 and a are equal? Yes
a1 == a ? Yes
b and bcopy are equal ? Yes
b == bcopy ? Yes
클래스 예제
다음 예제에서는 이 규칙을 위반하는 클래스(참조 형식)를 보여 줍니다.
using System;
namespace Samples
{
// Violates this rule
public class Point
{
private readonly int _X;
private readonly int _Y;
public Point(int x, int y)
{
_X = x;
_Y = y;
}
public int X
{
get { return _X; }
}
public int Y
{
get { return _Y; }
}
public override int GetHashCode()
{
return _X ^ _Y;
}
public static bool operator ==(Point point1, Point point2)
{
if (point1 == null || point2 == null)
return false;
if (point1.GetType() != point2.GetType())
return false;
if (point1._X != point2._X)
return false;
return point1._Y == point2._Y;
}
public static bool operator !=(Point point1, Point point2)
{
return !(point1 == point2);
}
}
}
다음 예에서는 System.Object.Equals를 재정의하여 위반을 수정합니다.
using System;
namespace Samples
{
public class Point
{
private readonly int _X;
private readonly int _Y;
public Point(int x, int y)
{
_X = x;
_Y = y;
}
public int X
{
get { return _X; }
}
public int Y
{
get { return _Y; }
}
public override int GetHashCode()
{
return _X ^ _Y;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
Point point = (Point)obj;
if (_X != point.X)
return false;
return _Y == point.Y;
}
public static bool operator ==(Point point1, Point point2)
{
return Object.Equals(point1, point2);
}
public static bool operator !=(Point point1, Point point2)
{
return !Object.Equals(point1, point2);
}
}
}
구조체 예제
다음 예제에서는 이 규칙을 위반하는 구조체(값 형식)를 보여 줍니다.
using System;
namespace Samples
{
// Violates this rule
public struct Point
{
private readonly int _X;
private readonly int _Y;
public Point(int x, int y)
{
_X = x;
_Y = y;
}
public int X
{
get { return _X; }
}
public int Y
{
get { return _Y; }
}
public override int GetHashCode()
{
return _X ^ _Y;
}
public static bool operator ==(Point point1, Point point2)
{
if (point1._X != point2._X)
return false;
return point1._Y == point2._Y;
}
public static bool operator !=(Point point1, Point point2)
{
return !(point1 == point2);
}
}
}
다음 예에서는 System.ValueType.Equals를 재정의하여 위반을 수정합니다.
using System;
namespace Samples
{
public struct Point : IEquatable<Point>
{
private readonly int _X;
private readonly int _Y;
public Point(int x, int y)
{
_X = x;
_Y = y;
}
public int X
{
get { return _X; }
}
public int Y
{
get { return _Y; }
}
public override int GetHashCode()
{
return _X ^ _Y;
}
public override bool Equals(object obj)
{
if (!(obj is Point))
return false;
return Equals((Point)obj);
}
public bool Equals(Point other)
{
if (_X != other._X)
return false;
return _Y == other._Y;
}
public static bool operator ==(Point point1, Point point2)
{
return point1.Equals(point2);
}
public static bool operator !=(Point point1, Point point2)
{
return !point1.Equals(point2);
}
}
}
관련 규칙
CA1046: 참조 형식에 같음 연산자를 오버로드하지 마십시오.
CA2225: 연산자 오버로드에는 명명된 대체 항목이 있습니다.
CA2226: 연산자에는 대칭 오버로드가 있어야 합니다.
피드백
https://aka.ms/ContentUserFeedback을 참조하세요.
출시 예정: 2024년 내내 콘텐츠 피드백 메커니즘인 GitHub 문제를 단계적으로 폐지하고 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은다음에 대한 사용자 의견 제출 및 보기