I want to understand the scenarios where IEqualityComparer<T>
and IEquatable<T>
should be used. The MSDN documentation for both looks very similar.
我想了解IEqualityComparer
5 个解决方案
#1
96
IEqualityComparer<T>
is an interface for an object that performs the comparison on two objects of the type T
.
IEqualityComparer
IEquatable<T>
is for an object of type T
so that it can compare itself to another.
IEquatable
#2
39
When deciding whether to use IEquatable<T>
or IEqualityComparer<T>
, one could ask:
当决定是否使用IEquatable
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, thenIEquatable<T>
would be the right choice: This interface is supposed to be implemented only byT
itself, so that one instance ofT
has internal knowledge of how to compare itself to another instance ofT
.如果只有一种方法测试T为平等的两个实例,或者几个方法之一是首选,然后IEquatable < T >将会正确的选择:这个接口应该是只有T本身实现,这样一个实例(T)的内部知识如何比较T的另一个实例。
-
On the other hand, if there are several equally reasonable methods of comparing two
T
s for equality,IEqualityComparer<T>
would seem more appropriate: This interface is not meant to be implemented byT
itself, but by other "external" classes. Therefore, when testing two instances ofT
for equality, becauseT
has no internal understanding of equality, you will have to make an explicit choice of aIEqualityComparer<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
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
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
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
#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 T
s. The other can compare itself to other T
s. 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
IEquatable<T>
is for an object of type T
so that it can compare itself to another.
IEquatable
#2
39
When deciding whether to use IEquatable<T>
or IEqualityComparer<T>
, one could ask:
当决定是否使用IEquatable
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, thenIEquatable<T>
would be the right choice: This interface is supposed to be implemented only byT
itself, so that one instance ofT
has internal knowledge of how to compare itself to another instance ofT
.如果只有一种方法测试T为平等的两个实例,或者几个方法之一是首选,然后IEquatable < T >将会正确的选择:这个接口应该是只有T本身实现,这样一个实例(T)的内部知识如何比较T的另一个实例。
-
On the other hand, if there are several equally reasonable methods of comparing two
T
s for equality,IEqualityComparer<T>
would seem more appropriate: This interface is not meant to be implemented byT
itself, but by other "external" classes. Therefore, when testing two instances ofT
for equality, becauseT
has no internal understanding of equality, you will have to make an explicit choice of aIEqualityComparer<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
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
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
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
#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 T
s. The other can compare itself to other T
s. Usually, you'll only need to use one at at time, not both.
一个比较两个Ts,另一个比较自己和其他Ts。通常,你只需要一次使用一个,而不是同时使用两个。