어디 IEqualityComparer<T>
에서 IEquatable<T>
사용해야 하는 시나리오를 이해하고 싶습니다 . 두 가지에 대한 MSDN 설명서는 매우 비슷합니다.
T
구현을 위한 사용자 지정 컬렉션을 만들어야 함을 나타냅니다 IEquatable<T>
. List<T>
그렇지 않으면 컬렉션 에 미묘한 버그가 있습니까?
어디 IEqualityComparer<T>
에서 IEquatable<T>
사용해야 하는 시나리오를 이해하고 싶습니다 . 두 가지에 대한 MSDN 설명서는 매우 비슷합니다.
T
구현을 위한 사용자 지정 컬렉션을 만들어야 함을 나타냅니다 IEquatable<T>
. List<T>
그렇지 않으면 컬렉션 에 미묘한 버그가 있습니까?
답변:
IEqualityComparer<T>
유형의 두 객체에 대한 비교를 수행하는 객체에 대한 인터페이스입니다 T
.
IEquatable<T>
T
동일한 유형의 다른 객체와 비교할 수 있도록 유형의 객체를위한 것입니다 .
IEqualityComparer<T>
객체에 대한 인터페이스이다 (행 경량 다른 클래스는 통상 T
) 에서 비교 동작 기능을 제공T
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<>
다른 유형은 상속 하지 않습니까?
이론적으로 두 유형의 두 인스턴스를 비교하는 현명한 방법은 하나뿐입니다. 두 인스턴스의 X
및 Y
속성 이 동일한 경우 동일합니다. 이 생각에 따르면 두 유형 모두 구현해야합니다.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>
구현 이므로 목적에 충분하지 않은 경우 간단히 교체 할 수 있습니다.
IEqualityComparer<T>
구현 은 동등성 관계를 구현 해야 하기 때문에 이중 점 평등을 테스트하기 위해 제안 된 비교 방법이 깨졌습니다. 이는 두 객체가 1/3과 비교되는 모든 경우 에 서로 동일하게 비교 되어야 함을 의미합니다. 위와 반대되는 방식 IEquatable<T>
또는 IEqualityComparer<T>
방식으로 구현 된 모든 클래스 가 손상됩니다.
IEqualityComparer<String>
"hello"와 "hElLo"를 모두 "hello"로 간주 하는 a 는 "Hello"와 "hElLo"를 서로 동일하게 고려해야하지만 대부분의 비교 방법에서는 문제가되지 않습니다.
GetHashCode
두 값이 다른지 여부를 신속하게 결정할 수 있어야합니다. 규칙은 대략 다음과 같습니다. (1) GetHashCode
항상 동일한 값에 대해 동일한 해시 코드를 생성해야합니다. (2) GetHashCode
는 빨라야합니다 (보다 빠름 Equals
). (3) GetHashCode
정확하지 않아도됩니다 (만큼 정확하지는 않음 Equals
). 이는 다른 값에 대해 동일한 해시 코드를 생성 할 수 있음을 의미합니다. 더 정확하게 만들수록 더 좋을지 모르지만 빨리 유지하는 것이 더 중요합니다.
당신은 이미 그들이 무엇인지에 대한 기본 정의를 얻었습니다 . 즉, IEquatable<T>
클래스 T
에서 구현 하는 경우 Equals
유형의 객체에 대한 메소드 T
는 객체 자체 (동일성 테스트 대상)가 동일한 유형의 다른 인스턴스와 같은지 여부를 알려줍니다 T
. 반면, 의 인스턴스 범위를 벗어나는 IEqualityComparer<T>
두 인스턴스의 동등성을 테스트하기위한 것 T
입니다 T
.
에 관해서는 그들이 무엇을 위해 처음에는 혼란 스러울 수 있습니다. IEquatable<T>
정의에서 (클래스 T
자체에 정의 된 ) 객체 / 인스턴스의 고유성을 나타내는 사실상의 표준 이어야한다는 것이 분명 해야합니다. HashSet<T>
, Dictionary<T, U>
(고려 GetHashCode
뿐만 아니라, 오버라이드 (override)) Contains
에 List<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()
obj.Age.GetHashCode
. 편집합니다.
person.GetHashCode
어디 .... 왜 그렇게 무시할 것인가? -우리의 요점은 IEqualityComparer
규칙에 따라 다른 비교 구현을해야 하기 때문에 무시합니다-우리 가 잘 알고있는 규칙.
Age
속성 을 기준으로해야하므로을 호출 Age.GetHashCode
합니다. Age는 유형 int
이지만 .NET의 해시 코드 계약은 유형에 관계없이 그 유형입니다 different objects can have equal hash but equal objects cant ever have different hashes
. 이것은 우리가 맹목적으로 믿을 수있는 계약입니다. 우리의 맞춤 비교 자들도이 규칙을 준수해야합니다. 호출 someObject.GetHashCode
이 문제를 일으킨다면, 유형의 구현 자에 문제가있는 someObject
것이지 우리의 문제가 아닙니다.
IEqualityComparer는 두 개체의 동등성이 외부에서 구현 될 때 사용됩니다 (예 : 소스가없는 두 가지 유형에 대한 비교자를 정의하려는 경우 또는 두 상황 간의 동등성이 일부 제한된 컨텍스트에서만 의미가있는 경우).
IEquatable은 객체 자체 (평등을 위해 비교되는 것)가 구현하는 것입니다.
EqualityComparer<T>
대신 때문에 인터페이스 "구현EqualityComparer<T>
테스트 평등 사용IEquatable<T>