IEqualityComparer <T>와 IEquatable <T>의 차이점은 무엇입니까?


151

어디 IEqualityComparer<T>에서 IEquatable<T>사용해야 하는 시나리오를 이해하고 싶습니다 . 두 가지에 대한 MSDN 설명서는 매우 비슷합니다.


1
MSDN sez : "이 인터페이스를 통해 컬렉션에 대한 사용자 정의 된 동등 비교 구현할 수 있습니다 . "물론 선택된 답변에서 추론됩니다. MSDN은 상속 권장 EqualityComparer<T>대신 때문에 인터페이스 "구현 EqualityComparer<T>테스트 평등 사용IEquatable<T>
radarbob

... 위의 내용은 T구현을 위한 사용자 지정 컬렉션을 만들어야 함을 나타냅니다 IEquatable<T>. List<T>그렇지 않으면 컬렉션 에 미묘한 버그가 있습니까?
radarbob


@RamilShavaleev 링크가 끊어졌습니다
ChessMax

답변:


117

IEqualityComparer<T>유형의 두 객체에 대한 비교를 수행하는 객체에 대한 인터페이스입니다 T.

IEquatable<T>T동일한 유형의 다른 객체와 비교할 수 있도록 유형의 객체를위한 것입니다 .


1
같은 차이가 IComparable / IComparer
boctulus의

3
명백한 선장
스테판 Ivanenko

(편집)은 IEqualityComparer<T>객체에 대한 인터페이스이다 (행 경량 다른 클래스는 통상 T) 에서 비교 동작 기능을 제공T
rwong

61

IEquatable<T>또는 사용 여부를 결정할 때 IEqualityComparer<T>다음을 요청할 수 있습니다.

두 인스턴스가 T동일한 지 테스트하는 선호되는 방법이 있습니까 , 아니면 동일한 방법으로 여러 가지가 있습니까?

  • 두 인스턴스 가 동일한 지 테스트 T하는 한 가지 방법이 있거나 여러 방법 중 하나를 선호하는 IEquatable<T>경우 올바른 선택이 될 것입니다.이 인터페이스는 T자체적으로 만 구현 되므로 한 인스턴스의 T내부 지식이 방법의 다른 인스턴스에 자신을 비교 T.

  • 다른 한편으로, T동등성을 위해 두 s를 비교하는 똑같이 합리적인 여러 방법이 있다면 IEqualityComparer<T>더 적절 해 보일 것 T입니다. 따라서 T평등 에 대한 두 가지 인스턴스를 테스트 할 때는 평등 에 대한 T내부 이해가 없으므로 IEqualityComparer<T>특정 요구 사항에 따라 테스트를 수행 하는 인스턴스를 명시 적으로 선택 해야합니다.

예:

이 두 가지 유형 ( 값 의미론 이 있어야 함 )을 고려하십시오.

interface IIntPoint : IEquatable<IIntPoint>
{
    int X { get; }
    int Y { get; }
}

interface IDoublePoint  // does not inherit IEquatable<IDoublePoint>; see below.
{
    double X { get; }
    double Y { get; }
}

왜 이러한 유형 중 하나만 상속 받지만 IEquatable<>다른 유형은 상속 하지 않습니까?

이론적으로 두 유형의 두 인스턴스를 비교하는 현명한 방법은 하나뿐입니다. 두 인스턴스의 XY속성 이 동일한 경우 동일합니다. 이 생각에 따르면 두 유형 모두 구현해야합니다.IEquatable<> 평등 테스트를 수행하는 다른 의미있는 방법이 없을 것 같으므로 .

여기서 문제는 미세 반올림 오류로 인해 부동 소수점 숫자가 동일한 지 비교하는 것이 예상대로 작동하지 않을 수 있다는 것 입니다. 이 부동 소수점 숫자를 비교하는 다른 방법입니다 거의 평등 , 특정 장점과 트레이드 오프 각각은, 당신은 적합한 방법을 직접 선택할 수 있도록 할 수 있습니다.

sealed class DoublePointNearEqualityComparerByTolerance : IEqualityComparer<IDoublePoint>
{
    public DoublePointNearEqualityComparerByTolerance(double tolerance) {  }
    
    public bool Equals(IDoublePoint a, IDoublePoint b)
    {
        return Math.Abs(a.X - b.X) <= tolerance  &&  Math.Abs(a.Y - b.Y) <= tolerance;
    }
    
}

위의 (위)에 링크 된 페이지에는 거의 평등에 대한이 테스트에 약점이 있다고 명시되어 있습니다. 이것은 IEqualityComparer<T>구현 이므로 목적에 충분하지 않은 경우 간단히 교체 할 수 있습니다.


6
합법적 인 IEqualityComparer<T>구현 동등성 관계를 구현 해야 하기 때문에 이중 점 평등을 테스트하기 위해 제안 된 비교 방법이 깨졌습니다. 이는 두 객체가 1/3과 비교되는 모든 경우 에 서로 동일하게 비교 되어야 함을 의미합니다. 위와 반대되는 방식 IEquatable<T>또는 IEqualityComparer<T>방식으로 구현 된 모든 클래스 가 손상됩니다.
supercat

5
더 좋은 예는 문자열 간의 비교입니다. 문자열이 동일한 바이트 시퀀스를 포함하는 경우에만 문자열을 동일하게 간주하는 문자열 비교 방법을 사용하는 것이 좋지만 대소 문자를 구분하지 않는 비교와 같이 등가 관계를 구성하는 다른 유용한 비교 방법 도 있습니다 . IEqualityComparer<String>"hello"와 "hElLo"를 모두 "hello"로 간주 하는 a 는 "Hello"와 "hElLo"를 서로 동일하게 고려해야하지만 대부분의 비교 방법에서는 문제가되지 않습니다.
supercat

@supercat, 소중한 피드백에 감사드립니다. 앞으로 며칠 내로 답변을 수정하지 않을 가능성이 높으므로 원하는 경우 자유롭게 수정하십시오.
stakx-더 이상

이것이 바로 내가 필요한 것과 내가하고있는 일입니다. 그러나 값이 다르면 false를 리턴하는 GetHashCode를 대체해야합니다. GetHashCode를 어떻게 처리합니까?
teapeng

@teapeng : 무슨 구체적인 사용 사례에 대해 잘 모르겠습니다. 일반적으로 GetHashCode두 값이 다른지 여부를 신속하게 결정할 수 있어야합니다. 규칙은 대략 다음과 같습니다. (1) GetHashCode 항상 동일한 값에 대해 동일한 해시 코드를 생성해야합니다. (2) GetHashCode 는 빨라야합니다 (보다 빠름 Equals). (3) GetHashCode 정확하지 않아도됩니다 (만큼 정확하지는 않음 Equals). 이는 다른 값에 대해 동일한 해시 코드를 생성 할 수 있음을 의미합니다. 더 정확하게 만들수록 더 좋을지 모르지만 빨리 유지하는 것이 더 중요합니다.
stakx-더 이상

27

당신은 이미 그들이 무엇인지에 대한 기본 정의를 얻었습니다 . 즉, IEquatable<T>클래스 T에서 구현 하는 경우 Equals유형의 객체에 대한 메소드 T는 객체 자체 (동일성 테스트 대상)가 동일한 유형의 다른 인스턴스와 같은지 여부를 알려줍니다 T. 반면, 의 인스턴스 범위를 벗어나는 IEqualityComparer<T>두 인스턴스의 동등성을 테스트하기위한 것 T입니다 T.

에 관해서는 그들이 무엇을 위해 처음에는 혼란 스러울 수 있습니다. IEquatable<T>정의에서 (클래스 T자체에 정의 된 ) 객체 / 인스턴스의 고유성을 나타내는 사실상의 표준 이어야한다는 것이 분명 해야합니다. HashSet<T>, Dictionary<T, U>(고려 GetHashCode뿐만 아니라, 오버라이드 (override)) ContainsList<T>이의 등 메이크업 사용. 구현 IEqualityComparer<T>에 대한 것은 T위에서 언급 한 일반적인 경우 도움이되지 않습니다. 결과적으로, IEquatable<T>이외의 다른 클래스 에서 구현할 가치가 거의 없습니다 T. 이:

class MyClass : IEquatable<T>

거의 말이되지 않습니다.

반면에

class T : IEquatable<T>
{
    //override ==, !=, GetHashCode and non generic Equals as well

    public bool Equals(T other)
    {
        //....
    }
}

그것이 어떻게 이루어져야 하는가입니다.

IEqualityComparer<T>평등에 대한 사용자 지정 유효성 검사가 필요한 경우에 유용하지만 일반적인 규칙은 아닙니다. 예를 들어, Person어느 시점에서 어떤 나이에 따라 두 사람의 평등을 테스트해야 할 수도 있습니다. 이 경우 다음을 수행 할 수 있습니다.

class Person
{
    public int Age;
}

class AgeEqualityTester : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.Age == y.Age;
    }

    public int GetHashCode(Person obj)
    {
        return obj.Age.GetHashCode;
    }
}

테스트하려면

var people = new Person[] { new Person { age = 23 } };
Person p = new Person() { age = 23 };

print people.Contains(p); //false;
print people.Contains(p, new AgeEqualityTester()); //true

마찬가지로 IEqualityComparer<T>T이해가되지 않습니다.

class Person : IEqualityComparer<Person>

사실 이것은 효과가 있지만 눈에는 좋지 않으며 논리를 물리칩니다.

일반적으로 필요한 것은 IEquatable<T>입니다. 또한 다른 기준에 따라 IEquatable<T>여러 개가 IEqualityComparer<T>가능 하지만 하나만 가질 수 있습니다 .

IEqualityComparer<T>하고 IEquatable<T>정확하게 유사하다 Comparer<T>IComparable<T>비교 목적이 아니라 동일시하는 것보다 사용하는; 여기 에 같은 대답을 쓴 좋은 실이 있습니다 :)


public int GetHashCode(Person obj)반환해야합니다obj.GetHashCode()
hyankov

@HristoYankov가 반환해야합니다 obj.Age.GetHashCode. 편집합니다.
nawfal

비교자가 객체의 해시와 비교할 때 왜 그런 가정을해야하는지 설명해주세요. 귀하의 비교기는 Person이 해시를 어떻게 계산하는지 모르는 이유는 무엇입니까?
hyankov

@HristoYankov 사람이 해시 계산하는 방법을 귀하의 비교 자 알지 못한다 물론 그런 우리가 직접 호출하지 않은 이유는, - person.GetHashCode어디 .... 왜 그렇게 무시할 것인가? -우리의 요점은 IEqualityComparer규칙에 따라 다른 비교 구현을해야 하기 때문에 무시합니다-우리 가 잘 알고있는 규칙.
nawfal

이 예에서는 비교 Age속성 을 기준으로해야하므로을 호출 Age.GetHashCode합니다. Age는 유형 int이지만 .NET의 해시 코드 계약은 유형에 관계없이 그 유형입니다 different objects can have equal hash but equal objects cant ever have different hashes. 이것은 우리가 맹목적으로 믿을 수있는 계약입니다. 우리의 맞춤 비교 자들도이 규칙을 준수해야합니다. 호출 someObject.GetHashCode이 문제를 일으킨다면, 유형의 구현 자에 문제가있는 someObject것이지 우리의 문제가 아닙니다.
nawfal

11

IEqualityComparer는 두 개체의 동등성이 외부에서 구현 될 때 사용됩니다 (예 : 소스가없는 두 가지 유형에 대한 비교자를 정의하려는 경우 또는 두 상황 간의 동등성이 일부 제한된 컨텍스트에서만 의미가있는 경우).

IEquatable은 객체 자체 (평등을 위해 비교되는 것)가 구현하는 것입니다.


실제로 "평등에 연결"(외부 사용) 문제를 제기 한 사람은 귀하뿐입니다.
Royi Namir

4

하나는 두 개를 비교합니다 T. 다른 사람은 다른 사람과 비교할 수 있습니다 T. 일반적으로 한 번에 하나만 사용하면되고 둘 다 사용하지 않아도됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.