Comparator
I recently wrote a generic PriorityQueue class which can treat any type of object as the priority (not just integers). Specifically, the class looked like this:
public class PriorityQueue<T, TPriority>
{
public PriorityQueue()
: this(false)
{
...
}
public PriorityQueue(bool invert)
: this(Comparer<TPriority>.Default)
{
...
}
public PriorityQueue(IComparer<TPriority> comparer)
{
...
}
public void Enqueue(T item, TPriority priority)
{
...
}
public KeyValuePair<T, TPriority> Dequeue()
{
...
}
...
}
Since it allowed any type of object as the priority object, it obviously can't use the standard numerical < and > operators to compare them. Many classes in the .NET framework (such as List<T>) have this same pattern, so the framework provides an IComparer<T> interface and a Comparer<T> base class to support comparison of arbitrary types. The interface only has one method you have to implement: int Compare(T x, T y).
Every time I implement IComparer I think it's silly that I have to create a new class (which usually also means a new file) that just defines one method. In fact, the int Compare method is usually just a one-liner like String.Compare(x.SomeProperty, y.SomeProperty) since all I want to do is sort items based on SomeProperty. Why do I have to create a whole new class (and whole new file) just to specify String.Compare(x.SomeProperty, y.SomeProperty)?
Obviously someone in the .NET framework team felt the same way, so they introduced a Comparison<T> delegate and added overloads to Array.Sort<T> and List<T>.Sort which accept this delegate instead of requiring an implementation of the IComparer interface. Unfortunately they only added overloads for those two methods; there are still over twenty other methods in the .NET framework that require the IComparer<T> interface, including LINQ's IEnumerable<T> extension methods.
In order to use the single-delegate idea in all of the places that still require the interface, I created a new class called Comparator<T>:
public class Comparator<T> : Comparer<T>
{
private readonly Comparison<T> comparison;
public Comparator(Comparison<T> comparison)
{
this.comparison = comparison;
}
public override int Compare(T x, T y)
{
return this.comparison(x, y);
}
}
[Comments and argument checking omitted for brevity.]
This is probably the simplest class in my library. It just takes a Comparison<T> delegate in the constructor and implements Comparer<T> (which also implements IComparer and IComparer<T>) by simply calling the comparison function. This tiny little class allows you to use all of the IComparer-based methods and constructors (such as new SortedList(comparer), new SortedDictionary(comparer), IEnumerable<T>.OrderBy(), etc) without having to create a new class every time.