158

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

4

5 回答 5

129

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

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

于 2012-02-16T18:29:29.653 回答
66

在决定是否使用IEquatable<T>orIEqualityComparer<T>时,人们可能会问:

是否有测试两个实例T是否相等的首选方法,或者是否有几种同样有效的方法?

  • 如果只有一种方法可以测试两个实例T是否相等,或者如果首选几种方法之一,那么IEquatable<T>将是正确的选择:该接口应该仅由其T自身实现,因此一个实例T具有内部知识如何将自己与T.

  • 另一方面,如果有几种同样合理的方法来比较两个Ts 是否相等,那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>实现,如果它对您的目的不够好,您可以简单地将其换掉。

于 2013-01-25T13:29:20.820 回答
31

您已经了解了它们是什么的基本定义。简而言之,如果您IEquatable<T>在 class上实现,则type 对象上T的方法会告诉您对象本身(正在测试相等性的对象)是否等于相同 type 的另一个实例。然而,用于测试 的任何两个实例的相等性,通常在 的实例范围之外。EqualsTTIEqualityComparer<T>TT

至于它们的用途,起初可能会令人困惑。从定义中应该很清楚,因此IEquatable<T>(在类T本身中定义)应该是表示其对象/实例唯一性的事实标准。HashSet<T>, Dictionary<T, U>(考虑到GetHashCode也被覆盖),ContainsList<T>利用这个。实施IEqualityComparer<T>onT对上述一般情况没有帮助。随后,在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>onT没有意义。

class Person : IEqualityComparer<Person>

确实,这可行,但看起来不太好,并且不符合逻辑。

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

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

于 2012-12-06T18:40:02.653 回答
11

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

IEquatable 用于实现对象本身(被比较是否相等)。

于 2012-02-16T18:31:08.520 回答
4

一个比较两个Ts。other 可以将自己与其他Ts 进行比较。通常,您一次只需要使用一个,而不是同时使用两个。

于 2012-02-16T18:29:54.127 回答