IEqualityComparer <T>和IEquatable <T>有什么区别?

我想了解应该使用IEqualityComparer<T>IEquatable<T>的场景。 两个MSDN文档看起来非常相似。

IEqualityComparer<T>是一个对象的接口,用于对Ttypes的两个对象执行比较。

IEquatable<T>用于Ttypes的对象,以便它可以将自己与另一个对比。

当决定是否使用IEquatable<T>IEqualityComparer<T> ,可以问:

是否有一种testingT两个实例是否相等的首选方法,还是有几个同样有效的方法?

  • 如果只有一种方法来testingT两个实例是否相等,或者有几个方法中的一个是优先的,那么IEquatable<T>就是正确的select:这个接口应该只由T本身实现,这样一个T实例具有如何将自身与T另一个实例进行比较的内部知识。

  • 另一方面,如果有几个同等合理的方法比较两个T s是否相等, IEqualityComparer<T>看起来更合适:这个接口并不意味着由T本身实现,而是由其他“外部”类实现。 因此,在testingT两个实例是否相等时,由于T没有内部对等的理解,因此必须根据您的具体要求明确select执行testing的IEqualityComparer<T>实例。

例:

让我们考虑这两种types(应该是有价值的语义 ):

 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; } } 

为什么只有这些types之一会inheritanceIEquatable<> ,而不是其他的?

理论上,只有一种比较两种情况的明智方式:如果两种情况下的XY属性相等,则它们是相等的。 按照这个思路,这两种types都应该实现IEquatable<> ,因为似乎没有其他有意义的方法进行平等testing。

这里的问题是,由于细微的舍入错误 , 比较浮点数相等性可能无法按预期工作 。 有几种不同的方法比较近似平等的浮点数,每种方法都有特定的优点和折衷,您可能希望能够select适合自己的方法。

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

请注意,我链接到(上面)页面明确指出,这种testing近乎平等有一些弱点。 由于这是一个IEqualityComparer<T>实现,所以如果对于您的目的来说不够好,您可以将其交换出来。

你已经有了它们的基本定义。 简而言之,如果在类T上实现了IEquatable<T> ,那么IEquatable<T>types的对象上的Equals方法会告诉您对象本身(正在testing的是否相等)与另一个相同typesT实例相同。 而IEqualityComparer<T>用于testingIEqualityComparer<T>的任何两个实例的相等性,通常在T实例的范围之外。

至于他们是什么,可以混淆起初。 从定义中应该清楚,因此IEquatable<T> (在T类本身中定义)应该成为表示对象/实例唯一性的事实标准。 HashSet<T>Dictionary<T, U> (考虑GetHashCode也被重写), Contains List<T>等等。 在T上实现IEqualityComparer<T>并不能帮助上面提到的一般情况。 随后,除了IEquatable<T>任何其他类实现IEquatable<T>价值不大。 这个:

 class MyClass : IEquatable<T> 

很less有道理。

另一方面

 class T : IEquatable<T> { //override ==, !=, GetHashCode and non generic Equals as well public bool Equals(T other) { //.... } } 

是应该如何做的。

IEqualityComparer<T>在需要自定义相等性validation时非常有用,但不是一般规则。 例如,在某Person某个阶层,你可能需要根据他们的年龄来testing两个人的平等。 在这种情况下,你可以这样做:

 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; } } 

要testing它们,请尝试

 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>上的IEqualityComparer<T>没有任何意义。

 class Person : IEqualityComparer<Person> 

这确实有效,但对眼睛看起来并不好,并且打败了逻辑。

通常你需要的是IEquatable<T> 理想情况下,您可以只有一个IEquatable<T>而多个IEqualityComparer<T>可能基于不同的标准。

IEqualityComparer<T>IEquatable<T>完全类似于Comparer<T>IComparable<T> ,它们用于比较而不是等同; 这里的一个很好的线程,我写了相同的答案:)

IEqualityComparer用于当两个对象的等式是在外部实现的时候,例如,如果你想为两个没有源的types定义一个比较器,或者两个事物之间的相等只在某些有限的情况下才有意义。

IEquatable是为了实现对象本身(被比较的是相等的)。

一个比较两个T s。 另一个可以与其他T比较。 通常,你只需要一次使用一个,而不是两个。