In my latest post on the subject I briefly went over Linq and the OrderBy() method.
By the same time, while “researching” the web for material I came across the wonderful entry by John Miller and his example on JP’s generic ChainedComparer. I recommend reading it before going on as it is a beautiful example of simple, clean design to solve a problem.
At this point it was obvious to me that I was going to include something like that to my personal tool belt (credit due, of course) but then it struck me how different and “incompatible” IComparer<T>, Comparison<T>, ChainedComparer<T> and the key selector of Linq are. For one, a Comparison<T> is, of course, not an IComparer<T>, and a Linq key selector is neither a Comparison<T> nor an IComparer<T> itself. Also I felt I could polish the ChainedComparer API a bit, as its usage felt a bit clumsy for my liking.
So, what I did was, while in the process of importing John’s example to my personal utility library, try to accomplish this unification and the result I want to share with you all.
The first thing was to rename ChainedComparer to ChainableComparer as I like this better. Then I had to extend the IChainableComparer interface to allow me to chain not only IChainableComparers but also comparison delegates and key selectors:
Fine enough, but if I am to be able to chain other things than IChainableComparers I was going to need adapters. And so ComparisonComparer and FuncComparer came to “digital life”:
This one allow us to convert from a Comparison<T> to an IComparer<T> (as ChainableComparer<T> is also an IComparer<T>) and back again, using my not-much-appreciated implicit comparison operator. This way we can use this class in all possible scenarios.
And this one allows to create an IChainableComparer<T> from a key selector, but also give us some chances to get a Comparison<T> delegate from a key selector, should we need one.
With those types in place the modified version of the abstract class remains like:
Where each Then() overload is a way to create new IChainableComparer<T> implementation and Compare(T, T) invokes the chain of comparer whenever the compared element are equal.
I have omitted for brevity some factory methods that, in my opinion, improves the usage experience of the class. They are included in the source code, though.
And with this somewhat “advanced” topic I think I am going to close the theme Equality and Comparison.
It allowed me to dig deeper into the guts of the framework and I learn a lot in the process. I hope someone took something out of it too.