Suppose I’ve got a generic MyClass<T> that needs to compare two objects of type <T>. Usually I’d do something like …
void DoSomething(T o1, T o2)
{
if(o1.Equals(o2))
{
...
}
}
Now suppose my MyClass<T> has a constructor that supports passing a custom IEqualityComparer<T>, similar to Dictionary<T>. In that case I’d need to do …
private IEqualityComparer<T> _comparer;
public MyClass() {}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if((_comparer != null && _comparer.Equals(o1, o2)) || (o1.Equals(o2)))
{
...
}
}
To remove this lengthy if statement, it’d be good if I could have _comparer default to a ‘default comparer’ if the regular constructor is used. I searched for something like typeof(T).GetDefaultComparer() but wasn’t able to find anything like it.
I did find EqualityComparer<T>.Default, could I use that? And would then this snippet …
public MyClass()
{
_comparer = EqualityComparer<T>.Default;
}
void DoSomething(T o1, T o2)
{
if(_comparer.Equals(o1, o2))
{
...
}
}
… provide the same results as using o1.Equals(o2) for all possible cases?
(As a side note, would this mean I’d also need to use any special generic constraint for <T>?)
It should be the same, but it is not guaranteed, because it depends on implementation details of the type
T.Explanation:
Without a constraint to
T, o1.Equals(o2) will callObject.Equals, even ifTimplementsIEquatable<T>.EqualityComparer<T>.Defaulthowever, will useObject.Equalsonly, ifTdoesn’t implementIEquatable<T>. If it does implement that interface, it usesIEquatable<T>.Equals.As long as
T‘s implementation ofObject.Equalsjust callsIEquatable<T>.Equalsthe result is the same. But in the following example, the result is not the same:Now, it doesn’t make any sense to implement a class like this. But you will have the same problem, if the implementer of
MyObjectsimply forgot to overrideObject.Equals.Conclusion:
Using
EqualityComparer<T>.Defaultis a good way to go, because you don’t need to support buggy objects!