IEqualityComparer <t>和IEquatable <t>之间有什么区别?</t> </t>

时间:2012-02-16 18:27:50

标签: c# .net equals iequalitycomparer iequatable

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

5 个答案:

答案 0 :(得分:104)

IEqualityComparer<T>是一个对象的接口,它对T类型的两个对象执行比较。

IEquatable<T>用于T类型的对象,以便它可以将自己与另一个对象进行比较。

答案 1 :(得分:57)

在决定是否使用IEquatable<T>IEqualityComparer<T>时, 人们可以问:

  

是否有一种首选方法可以测试两个T实例的相等性,还是有几种同样有效的方法?

  • 如果只有一种方法可以测试两个T实例的相等性,或者如果首选几种方法中的一种,那么IEquatable<T>将是正确的选择:这个接口应该是仅由T本身实现,以便T的一个实例具有如何将自身与另一个T实例进行比较的内部知识。

  • 另一方面,如果有几种同样合理的方法来比较两个T的相等性,IEqualityComparer<T>似乎更合适:这个接口并不意味着{ {1}}本身,但由其他“外部”类。因此,在测试两个T实例的相等性时,由于T没有内部对等式的理解,因此您必须明确选择执行测试的T实例。您的具体要求。

示例:

让我们考虑这两种类型(应该有value semantics):

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,因为似乎没有其他有意义的方法来进行相等测试。

这里的问题是comparing floating-point numbers for equality might not work as expected, due to minute rounding errors。有不同的方法来比较 near-equality 的浮点数,每个方法都有特定的优点和权衡,你可能希望能够选择适合自己的方法。

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; } … } 实现,如果它不适合您的目的,您可以简单地将其交换出来。

答案 2 :(得分:23)

您已经获得了它们是什么的基本定义。简而言之,如果在类IEquatable<T>上实现TEquals类型对象上的T方法会告诉您对象本身(正在测试的是否相等)等于同一类型T的另一个实例。鉴于IEqualityComparer<T>用于测试T的任意两个实例的相等性,通常超出T实例的范围。

至于它们的用途一开始可能会令人困惑。从定义中可以清楚地看出,因此IEquatable<T>(在类T本身中定义)应该是表示其对象/实例的唯一性的事实标准。 HashSet<T>Dictionary<T, U>(同时考虑GetHashCode被覆盖),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>和{{1}}完全相似,用于比较而非等同;一个好的帖子here我在那里写了相同的答案:)

答案 3 :(得分:10)

IEqualityComparer用于在外部实现两个对象的相等时,例如,如果你想为你没有源的两种类型定义一个比较器,或者两种事物之间的相等只在某些有限的上下文中有意义的情况。

IEquatable用于实现对象本身(要进行相等的比较)。

答案 4 :(得分:4)

比较两个T。另一个可以与其他T进行比较。通常,您只需要在时间使用一个,而不是两个。