C#에서 모든 객체는 object를 상속받고 obejct내에 정의되어 있는 기본 함수들을 사용할 수 있다. 이 중 Equals 함수에서 불필요한 Boxing/Unboxing이 발생할 수 있다.
아래 예제는 Point 클래스에서 Equals 함수를 재정의를 하고 이를 사용하는 예제이다.
class Point
{
private int x;
private int y;
public Point(int xPos, int yPos)
{
x = xPos;
y = yPos;
}
public override bool Equals(object? obj)
{
Point pt = (Point)obj;
return x == pt.x && y == pt.y;
}
}
class Program
{
public static void Main(string[] args)
{
Point p1 = new Point(1, 1);
Point p2 = new Point(1, 1);
Console.WriteLine(p1.Equals(p2));
}
}
CompareTo와 다르게 Equals는 기본적으로 object를 매개변수로 받는 함수를 오버라이드할 수 있다. 하지만 Point가 구조체일 경우에 Boxing/Unboxing이 발생하게 된다.
이를 위해 C#에서 IEquatable<T>라는 인터페이스를 제공한다. Generic으로 되어 있어 값타입 매개변수를 받는 Equals 함수를 정의할 수 있다. IEquatable<T>를 사용하는 방법은 인터페이스를 구현하는 것이기 때문에 override 키워드를 사용하지 않는 것에 주의하자.

아래 코드는 위 예제에서 Point를 구조체로 바꾸었을 때 IEquatable<T>의 Equals를 구현하는 예제이다.
struct Point: IEquatable<Point>
{
private int x;
private int y;
public Point(int xPos, int yPos)
{
x = xPos;
y = yPos;
}
public override bool Equals(object? obj)
{
Point pt = (Point)obj;
return x == pt.x && y == pt.y;
}
public bool Equals(Point other)
{
return x == other.x && y == other.y;
}
}
공식문서에서는 값타입의 경우 obejct.Equals와 IEquatable<T>의 Equals 둘다 정의할 것을 추천한다.