Today alone, I wrote articles about how IComparer works, using the proxy pattern to sort by multiple IComparers, and converting a Comparison delegate to an IComparer. Bragging aside though, I've found a fun way to combine my current favorite topics: IComparer and Extension Methods.
I wrote 3 extension methods to help me do some pretty neat things with IComparers and Comparisons. You'll see references to two of my prior articles in this post. The ComparerProxy sorts by multiple comparers and the ComparisonComparer converts a Comparison to an IComparer.
I'll show you the extension methods first, then I'll explain the reasoning behind them, and then I'll show you some usage.
public static class IComparerExtensionsSo, lately I've been pretty big on fluent interfaces. I haven't written one yet, but I do use extension methods to make my implementations look a little more fluent. That's why, when I wrote the ComparerProxy, I thought, "Hey, wouldn't be cool if I could just take an IComparer and tack another comparer onto it? And then another? And another?" That's why I wrote the IComparer.Then() extension method.
{
public static IComparer<T> Then<T>(this IComparer<T> priority, IComparer<T> then)
{
return new ComparerProxy<T>(priority, then);
}
public static IComparer<T> Invert<T>(this IComparer<T> comparer)
{
return new ComparisonComparer<T>((x, y) => comparer.Compare(x, y) * -1);
}
public static IComparer<T> ToComparer<T>(this Comparison<T> comparison)
{
return new ComparisonComparer<T>(comparison);
}
}
Next, I realized that if you have a Comparison delegate, it'd be nice to be able to add that to a list of IComparers so I added the ToComparer method.
Finally, another thing that I often want to do is write an IComparer once but to be able to use it in reverse. Id est, I want to invert the logic. Obviously, I could List.Sort() and List.Reverse(), but that's much less efficient than having a CaseInsensitiveComparer and a ReverseCaseInsensitiveComparer.
The problem is, I don't really want to have to write both of those comparers. Instead, now I can call IComparer.Invert() and I get an IComparer that performs exactly like the original, but with inverted logic.
So, without further ado, here are some usage examples. I'm using the same test setup as I did with the ComparerProxy. I've also created several more IComparers to try out:
Comparison<Person> length = (x, y) => x.ToString().Length - y.ToString().Length;I executed the following lines which produced the commented results:
IComparer<Person> lengthLast = new ComparerProxy<Person>(length.ToComparer(), last);
IComparer<Person> lastFirstComposed = last.Then(first);
_folks.Sort(length);
PrintList(_folks);
// Woody, Pete
// Woody, Lauren
// Caldwell, Cory
// Caldwell, Colin
// Brechtel, Jamus
// Woody, Royce Ann
// Brechtel, Ashley
// Caldwell, Jennifer
_folks.Sort(lengthLast);
PrintList(_folks);
// Woody, Pete
// Woody, Lauren
// Caldwell, Cory
// Brechtel, Jamus
// Caldwell, Colin
// Brechtel, Ashley
// Woody, Royce Ann
// Caldwell, Jennifer
_folks.Sort(lastFirstComposed);
PrintList(_folks);
// Brechtel, Ashley
// Brechtel, Jamus
// Caldwell, Colin
// Caldwell, Cory
// Caldwell, Jennifer
// Woody, Lauren
// Woody, Pete
// Woody, Royce Ann
_folks.Sort(last.Invert().Then(first));
PrintList(_folks);
// Woody, Lauren
// Woody, Pete
// Woody, Royce Ann
// Caldwell, Colin
// Caldwell, Cory
// Caldwell, Jennifer
// Brechtel, Ashley
// Brechtel, Jamus
No comments:
Post a Comment