How are equality comparisons performed?
Whenever the BCL classes want to perform an equality check between objects of some type T
, they do so by calling one or both of the methods in some implementation of IEqualityComparer<T>
. To get hold of such an implementation, the framework looks to EqualityComparer<T>.Default
.
As mentioned in the documentation, this property produces an IEqualityComparer<T>
like this:
The Default property
checks whether type T implements the
System.IEquatable<T>
interface and, if so, returns an
EqualityComparer<T>
that uses that implementation. Otherwise, it
returns an EqualityComparer<T>
that uses the overrides of
Object.Equals
and Object.GetHashCode
provided by T
.
What are my options?
So, in general, to dictate how equality comparisons should be performed you can:
- Explicitly provide an implementation of
IEqualityComparer<T>
to the class or method that performs equality checks. This option is not very visible with List<T>
, but many LINQ methods (such as Contains
) do support it.
- Make your class implement
IEquatable<T>
. This will make EqualityComparer<T>.Default
use this implementation, and is a good choice whenever there is an obvious "natural" way to compare objects of type T
.
- Override
object.GetHashCode
and object.Equals
without implementing IEqualityComparer<T>
. However, this is simply an inferior version of #2 and AFAIK should always be avoided.
Which option to pick?
A good rule of thumb is: if there is an obvious and natural way to compare objects of class T
, consider having it implement IEquatable<T>
; this will make sure your comparison logic is used throughout the framework without any additional involvement. If there is no obvious candidate, or if you want to compare in a manner different than the default, implement your own IEqualityComparer<T>
and pass the implementation as an argument to the class or method that needs to perform equality checks.