Implementing IEqualityComparer<T>
doesn't override
the base implementation of GetHashCode
and Equals
.
Implementing IEqualityComparer<T>
allows you to supply an instance of the implementor as an equality comparer for T
. This is a common parameter to several linq extensions and generic collection constructors.
Overriding Equals
and GetHashCode
effects the way instances of a class are tested for equality. Tapping into other implmentations that call Equals
and GetHashCode
, like the base =
and !=
operators and linq extensions and generic collection constructors where you don't supply an alternative IEqualityComparer<T>
.
These concepts are similar but serve different purposes, they are not partially interchangable.
Let me expand with an example,
public class A
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = (hash * 23) +
StringComparer.Ordinal.GetHashCode(this.Value1);
hash = (hash * 23) + this.Value2;
return hash;
}
}
public override bool Equals(object obj)
{
var a = obj as A;
if (a == null)
{
return false;
}
if (a.Value2 != this.Value2)
{
return false;
}
return StringComparer.Ordinal.Equals(
a.Value1,
this.Value1);
}
}
This implementation of A
correctly overrides Equals
and GetHashCode
, this change is sufficient to ensure that after calling the linq extension
var distinct = aSequneceOfA.Distinct();
distinct
will not contain any instances that have both the same Value2
and ordinally comparable Value1
. No other interface implementation is necessary to achieve this.
Now, suppose that in some situation I wasn't happy with this ordinal comparison for Value1
, perhaps I require some case insensitivity. I might implement an new equality comparer.
public class AComparerInsensitive : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
if (x == null)
{
return y == null;
}
if (y == null)
{
return false;
}
if (x.Value2 != y.Value2)
{
return false;
}
return StringComparer.CurrentCultureIgnoreCase.Equals(
x.Value1,
y.Value1)
}
public int GetHashCode(A a)
{
if (a == null)
{
return 0;
}
unchecked
{
int hash = 17;
hash = (hash * 23) +
StringComparer.CurrentCultureIgnoreCase.GetHashCode(
a.Value1);
hash = (hash * 23) + a.Value2;
return hash;
}
}
}
This would allow me to call the alternative overload of Distinct
,
var insensitivelyDistinct = aSequneceOfA.Distinct(
new AComparerInsensitive());
This overload of distinct ingnores A
s overridden Equals
and GetHashCode
and uses AComparerInsensitive
to perform the comparison.