IEqualityComparer和IEquatable有什么区别?

时间:2021-09-05 16:24:10

I want to understand the scenarios where IEqualityComparer<T> and IEquatable<T> should be used. The MSDN documentation for both looks very similar.

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

5 个解决方案

#1


96  

IEqualityComparer<T> is an interface for an object that performs the comparison on two objects of the type T.

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

IEquatable<T> is for an object of type T so that it can compare itself to another.

IEquatable 是一个T类型的对象,它可以与另一个对象进行比较。

#2


39  

When deciding whether to use IEquatable<T> or IEqualityComparer<T>, one could ask:

当决定是否使用IEquatable 或IEqualityComparer 时,可以问:

Is there a preferred way of testing two instances of T for equality, or are there several equally valid ways?

有没有一种方法可以测试两个T实例的相等性,或者有几种同样有效的方法?

  • If there is only one way of testing two instances of T for equality, or if one of several methods is preferred, then IEquatable<T> would be the right choice: This interface is supposed to be implemented only by T itself, so that one instance of T has internal knowledge of how to compare itself to another instance of T.

    如果只有一种方法测试T为平等的两个实例,或者几个方法之一是首选,然后IEquatable < T >将会正确的选择:这个接口应该是只有T本身实现,这样一个实例(T)的内部知识如何比较T的另一个实例。

  • On the other hand, if there are several equally reasonable methods of comparing two Ts for equality, IEqualityComparer<T> would seem more appropriate: This interface is not meant to be implemented by T itself, but by other "external" classes. Therefore, when testing two instances of T for equality, because T has no internal understanding of equality, you will have to make an explicit choice of a IEqualityComparer<T> instance which performs the test according to your specific requirements.

    另一方面,如果有几种同样合理的方法来比较两个Ts是否相等,那么IEqualityComparer 似乎更合适:这个接口不打算由T本身实现,而是由其他“外部”类实现。因此,当测试两个T实例是否相等时,由于T没有对等式的内部理解,您必须明确地选择iequalcomparer 实例,该实例根据您的特定需求执行测试。

Example:

例子:

Let's consider these two types (which are supposed to have value semantics):

让我们考虑这两种类型(它们应该具有值语义):

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

Why would only one of these types inherit IEquatable<>, but not the other?

为什么这些类型中只有一个继承了IEquatable<>,而另一个继承了呢?

In theory, there is only one sensible way of comparing two instances of either type: They are equal if the X and Y properties in both instances are equal. According to this thinking, both types should implement IEquatable<>, because it doesn't seem likely that there are other meaningful ways of doing an equality test.

在理论上,只有一种比较合理的方法来比较两种类型的实例:如果两个实例中的X和Y属性相等,那么它们是相等的。根据这种想法,这两种类型都应该实现IEquatable<>,因为似乎不太可能有其他有意义的方法来进行平等测试。

The issue here is that comparing floating-point numbers for equality might not work as expected, due to minute rounding errors. There are different methods of comparing floating-point numbers for near-equality, each with specific advantages and trade-offs, and you might want to be able to choose yourself which method is appropriate.

这里的问题是,由于微小的舍入错误,将浮点数与相等数进行比较可能不会像预期的那样工作。有不同的方法可以将浮点数与接近相等数进行比较,每种方法都具有特定的优点和优缺点,您可能希望能够自己选择合适的方法。

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

Note that the page I linked to (above) explicitly states that this test for near-equality has some weaknesses. Since this is a IEqualityComparer<T> implementation, you can simply swap it out if it's not good enough for your purposes.

请注意,我链接到(上面)的页面明确地指出,这个近乎平等的测试有一些弱点。由于这是一个IEqualityComparer 实现,您可以简单地交换它,如果它对您的目的不够好。

#3


17  

You have already got the basic definition of what they are. In short, if you implement IEquatable<T> on class T, the Equals method on an object of type T tells you if the object itself (the one being tested for equality) is equal to another instance of the same type T. Whereas, IEqualityComparer<T> is for testing the equality of any two instances of T, typically outside the scope of the instances of T.

你们已经有了它们的基本定义。简而言之,如果您实现IEquatable < T >类T,Equals方法类型T的对象告诉你如果对象本身(被测试的平等)等于另一个相同类型的实例T .然而,IEqualityComparer < T >是用于测试的平等的两个实例,通常的范围之外T的实例。

As to what they are for can be confusing at first. From the definition it should be clear that hence IEquatable<T> (defined in the class T itself) should be the de facto standard to represent uniqueness of its objects/instances. HashSet<T>, Dictionary<T, U> (considering GetHashCode is overridden as well), Contains on List<T> etc make use of this. Implementing IEqualityComparer<T> on T doesn't help the above mentioned general cases. Subsequently, there is little value for implementing IEquatable<T> on any other class other than T. This:

至于它们是什么,一开始可能会让人迷惑。从定义上应该很清楚,因此IEquatable (在类T本身中定义)应该是表示其对象/实例的惟一性的事实标准。HashSet , Dictionary (考虑到GetHashCode也被重写),包含在List 等中利用了这个。在T上实现IEqualityComparer 无助于上述一般情况。随后,在除T.之外的任何类上实现IEquatable 几乎没有什么价值: ,>

class MyClass : IEquatable<T>

rarely makes sense.

很少有意义。

On the other hand

另一方面

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

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

is how it should be done.

这是应该怎么做的。

IEqualityComparer<T> can be useful when you require a custom validation of equality, but not as a general rule. For instance, in a class of Person at some point you might require to test equality of two people based on their age. In that case you can do:

IEqualityComparer 在需要对等式进行自定义验证时很有用,但不是作为一般规则。例如,在某一类别的人中,你可能需要根据他们的年龄来测试两个人的平等程度。在这种情况下,你可以:

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

To test them, try

为了测试他们,试一试

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

Similarly IEqualityComparer<T> on T doesn't make sense.

同样,IEqualityComparer 在T上没有意义。

class Person : IEqualityComparer<Person>

True this works, but doesn't look good to eyes and defeats logic.

的确,这是可行的,但在眼睛看来不太好,而且会破坏逻辑。

Usually what you need is IEquatable<T>. Also ideally you can have only one IEquatable<T> while multiple IEqualityComparer<T> is possible based on different criteria.

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

The IEqualityComparer<T> and IEquatable<T> are exactly analogous to Comparer<T> and IComparable<T> which are used for comparison purposes rather than equating; a good thread here where I wrote the same answer :)

IEqualityComparer 和IEquatable 完全类似于比较器 和icom克莱伯 ,用于比较而不是等同;这里有个好线索,我写了同样的答案

#4


9  

IEqualityComparer is for use when the equality of two objects is externally implemented, e.g. if you wanted to define a comparer for two types that you did not have the source for, or for cases where equality between two things only makes sense in some limited context.

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

IEquatable is for the object itself (the one being compared for equality) to implement.

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

#5


4  

One compares two Ts. The other can compare itself to other Ts. Usually, you'll only need to use one at at time, not both.

一个比较两个Ts,另一个比较自己和其他Ts。通常,你只需要一次使用一个,而不是同时使用两个。

#1


96  

IEqualityComparer<T> is an interface for an object that performs the comparison on two objects of the type T.

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

IEquatable<T> is for an object of type T so that it can compare itself to another.

IEquatable 是一个T类型的对象,它可以与另一个对象进行比较。

#2


39  

When deciding whether to use IEquatable<T> or IEqualityComparer<T>, one could ask:

当决定是否使用IEquatable 或IEqualityComparer 时,可以问:

Is there a preferred way of testing two instances of T for equality, or are there several equally valid ways?

有没有一种方法可以测试两个T实例的相等性,或者有几种同样有效的方法?

  • If there is only one way of testing two instances of T for equality, or if one of several methods is preferred, then IEquatable<T> would be the right choice: This interface is supposed to be implemented only by T itself, so that one instance of T has internal knowledge of how to compare itself to another instance of T.

    如果只有一种方法测试T为平等的两个实例,或者几个方法之一是首选,然后IEquatable < T >将会正确的选择:这个接口应该是只有T本身实现,这样一个实例(T)的内部知识如何比较T的另一个实例。

  • On the other hand, if there are several equally reasonable methods of comparing two Ts for equality, IEqualityComparer<T> would seem more appropriate: This interface is not meant to be implemented by T itself, but by other "external" classes. Therefore, when testing two instances of T for equality, because T has no internal understanding of equality, you will have to make an explicit choice of a IEqualityComparer<T> instance which performs the test according to your specific requirements.

    另一方面,如果有几种同样合理的方法来比较两个Ts是否相等,那么IEqualityComparer 似乎更合适:这个接口不打算由T本身实现,而是由其他“外部”类实现。因此,当测试两个T实例是否相等时,由于T没有对等式的内部理解,您必须明确地选择iequalcomparer 实例,该实例根据您的特定需求执行测试。

Example:

例子:

Let's consider these two types (which are supposed to have value semantics):

让我们考虑这两种类型(它们应该具有值语义):

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

Why would only one of these types inherit IEquatable<>, but not the other?

为什么这些类型中只有一个继承了IEquatable<>,而另一个继承了呢?

In theory, there is only one sensible way of comparing two instances of either type: They are equal if the X and Y properties in both instances are equal. According to this thinking, both types should implement IEquatable<>, because it doesn't seem likely that there are other meaningful ways of doing an equality test.

在理论上,只有一种比较合理的方法来比较两种类型的实例:如果两个实例中的X和Y属性相等,那么它们是相等的。根据这种想法,这两种类型都应该实现IEquatable<>,因为似乎不太可能有其他有意义的方法来进行平等测试。

The issue here is that comparing floating-point numbers for equality might not work as expected, due to minute rounding errors. There are different methods of comparing floating-point numbers for near-equality, each with specific advantages and trade-offs, and you might want to be able to choose yourself which method is appropriate.

这里的问题是,由于微小的舍入错误,将浮点数与相等数进行比较可能不会像预期的那样工作。有不同的方法可以将浮点数与接近相等数进行比较,每种方法都具有特定的优点和优缺点,您可能希望能够自己选择合适的方法。

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

Note that the page I linked to (above) explicitly states that this test for near-equality has some weaknesses. Since this is a IEqualityComparer<T> implementation, you can simply swap it out if it's not good enough for your purposes.

请注意,我链接到(上面)的页面明确地指出,这个近乎平等的测试有一些弱点。由于这是一个IEqualityComparer 实现,您可以简单地交换它,如果它对您的目的不够好。

#3


17  

You have already got the basic definition of what they are. In short, if you implement IEquatable<T> on class T, the Equals method on an object of type T tells you if the object itself (the one being tested for equality) is equal to another instance of the same type T. Whereas, IEqualityComparer<T> is for testing the equality of any two instances of T, typically outside the scope of the instances of T.

你们已经有了它们的基本定义。简而言之,如果您实现IEquatable < T >类T,Equals方法类型T的对象告诉你如果对象本身(被测试的平等)等于另一个相同类型的实例T .然而,IEqualityComparer < T >是用于测试的平等的两个实例,通常的范围之外T的实例。

As to what they are for can be confusing at first. From the definition it should be clear that hence IEquatable<T> (defined in the class T itself) should be the de facto standard to represent uniqueness of its objects/instances. HashSet<T>, Dictionary<T, U> (considering GetHashCode is overridden as well), Contains on List<T> etc make use of this. Implementing IEqualityComparer<T> on T doesn't help the above mentioned general cases. Subsequently, there is little value for implementing IEquatable<T> on any other class other than T. This:

至于它们是什么,一开始可能会让人迷惑。从定义上应该很清楚,因此IEquatable (在类T本身中定义)应该是表示其对象/实例的惟一性的事实标准。HashSet , Dictionary (考虑到GetHashCode也被重写),包含在List 等中利用了这个。在T上实现IEqualityComparer 无助于上述一般情况。随后,在除T.之外的任何类上实现IEquatable 几乎没有什么价值: ,>

class MyClass : IEquatable<T>

rarely makes sense.

很少有意义。

On the other hand

另一方面

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

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

is how it should be done.

这是应该怎么做的。

IEqualityComparer<T> can be useful when you require a custom validation of equality, but not as a general rule. For instance, in a class of Person at some point you might require to test equality of two people based on their age. In that case you can do:

IEqualityComparer 在需要对等式进行自定义验证时很有用,但不是作为一般规则。例如,在某一类别的人中,你可能需要根据他们的年龄来测试两个人的平等程度。在这种情况下,你可以:

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

To test them, try

为了测试他们,试一试

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

Similarly IEqualityComparer<T> on T doesn't make sense.

同样,IEqualityComparer 在T上没有意义。

class Person : IEqualityComparer<Person>

True this works, but doesn't look good to eyes and defeats logic.

的确,这是可行的,但在眼睛看来不太好,而且会破坏逻辑。

Usually what you need is IEquatable<T>. Also ideally you can have only one IEquatable<T> while multiple IEqualityComparer<T> is possible based on different criteria.

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

The IEqualityComparer<T> and IEquatable<T> are exactly analogous to Comparer<T> and IComparable<T> which are used for comparison purposes rather than equating; a good thread here where I wrote the same answer :)

IEqualityComparer 和IEquatable 完全类似于比较器 和icom克莱伯 ,用于比较而不是等同;这里有个好线索,我写了同样的答案

#4


9  

IEqualityComparer is for use when the equality of two objects is externally implemented, e.g. if you wanted to define a comparer for two types that you did not have the source for, or for cases where equality between two things only makes sense in some limited context.

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

IEquatable is for the object itself (the one being compared for equality) to implement.

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

#5


4  

One compares two Ts. The other can compare itself to other Ts. Usually, you'll only need to use one at at time, not both.

一个比较两个Ts,另一个比较自己和其他Ts。通常,你只需要一次使用一个,而不是同时使用两个。