I want to understand the scenarios where IEqualityComparer
When deciding whether to use IEquatable
Is there a preferred way of testing two instances of
T
for equality, or are there several equally valid ways?
If there is only one way of testing two instances of T
for equality, or if one of several methods is preferred, then IEquatable
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
.
On the other hand, if there are several equally reasonable methods of comparing two T
s for equality, IEqualityComparer
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
instance which performs the test according to your specific requirements.
Example:
Let's consider these two types (which are supposed to have value semantics):
interface IIntPoint : IEquatable
{
int X { get; }
int Y { get; }
}
interface IDoublePoint // does not inherit IEquatable; see below.
{
double X { get; }
double Y { get; }
}
Why would only one of these types inherit IEquatable<>
, but not the other?
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.
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
{
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
implementation, you can simply swap it out if it's not good enough for your purposes.