From the IEqualityComparer<T> remarks section on MSDN:
-
We recommend that you derive from the
EqualityComparer<T> class instead of
implementing the IEqualityComparer<T>
interface, because the
EqualityComparer<T> class tests for
equality using the
IEquatable<T>.Equals method instead of
the Object.Equals method. …-
I don’t understand the quote’s argument of why we would should prefer to derive from
EqualityComparer<T>class instead of implementingIEqualityComparer<T>. It implies that objects implementingIEqualityComparer<T>will test for equality usingObject.Equals, but isn’t the whole point of implementingIEqualityComparer<T>when we don’t want to test for equality usingObject.EqualsorIEquatable<T>.Equals? -
It also implies that if we derive from
EqualityComparer<T>, then derived class will test for equality usingIEquatable<T>.Equalsmethod. Again, isn’t the whole point of deriving fromEqualityComparer<T>when we don’t want to test for equality usingObject.EqualsorIEquatable<T>.Equals(sinceEqualityComparer<T>.Defaultalready test usingObject.EqualsorIEquatable<T>.Equals)?
-
-
… This is consistent with the
Contains, IndexOf, LastIndexOf, and
Remove methods of the Dictionary<TKey,
TValue> class and other generic
collections.-
I assume most collections in the .NET library test for default equality of elements (i.e. when users don’t provide their own custom
IEqualityComparer<T>objects to these collections) by callingIEquatable<T>.EqualsorObject.Equals(depending on whether or not elements of typeTimplementIEquatable<T>) viaEqualityComparer<T>.Default. -
Why don’t these collections (when testing for default equality) call
IEquatable<T>.EqualsorObject.Equalsdirectly instead of viaEqualityComparer<T>.Defaultclass?
-
Regarding your first question:
The remarks section for the
IEqualityComparer<T>class doesn’t really seem to be providing a reason for why you should prefer deriving from the abstract class over the interface, it sounds more like a reason why the equality comparer interface exists in the first place. What it says there is practically useless, it’s basically describing what the default implementation is doing. If anything, the “reasoning” they’ve provided here sound more like a guideline of what your comparers could do and is irrelevant to what it actually does.Looking at the public/protected interface of the
EqualityComparer<T>class, there’s only one redeeming quality, it implements the non-genericIEqualityComparerinterface. I think what they meant to say that they recommend deriving from it becauseEqualityComparer<T>actually implements the non-genericIEqualityComparerinterface that way your class may be used where the non-generic comparer is required.It does make more sense in the remarks section for
IComparer<T>:I suspect it was supposed to say something similar for
IEqualityComparer<T>but some ideas were mixed up and ended up with an incomplete description.Regarding your second question:
A primary goal for the collections found in the library was to be as flexible as possible. One way to get that is to allow custom ways of comparing objects within them by providing a
IComparer<T>orIEqualityComparer<T>to do the comparisons. It would be much more easier to get an instance of a default comparer when one was not supplied than it is to do the comparisons directly. These comparers in turn could include the logic necessary to call the appropriate comparisons packaged nicely.e.g., The default comparers can determine whether
TimplementsIEquatable<T>and callIEquatable<T>.Equalson the object or otherwise useObject.Equals. Better encapsulated here in the comparer than it is potentially repeated in the collections code.Besides, if they wanted to fall back on calling
IEquatable<T>.Equalsdirectly, they would have to add a constraint onTthat would make this call possible. Doing so makes it less flexible and negates the benefits of providing the comparer in the first place.