Programming forums across the web are replete with questions about how to sort an IList. Many .NET developers have discovered that, unlike List<T>, IList<T> does not define a Sort() method. Although there are many excellent answers to the question of how to sort an IList<T> on the forums, none of them are as convenient, elegant, and complete as they could be.

Today, I will show you how to create a C# extension method to add Sort() functionality to IList<T> that behaves just like the List<T>.Sort() method. As a bonus, we can use the same technique to overload the LINQ Enumerable.OrderBy() extension method to allow it to accept a Comparison<T> delegate, rather than a key selector or IComparer<T>.

Get the code

The Goal: How we want IList<T> sorting to work.

If you’re a C# developer, chances are you’ve used the List<T> class and its built-in Sort() method, which provides very convenient syntax to sort a list in-place using a lambda expression.

Let’s look at a simple example. Say we have a list of names that we want to sort by string length:

List<string> list = new List<string> 
{ 
	"Carlton", "Alison", "Bob", "Eric", "David"
};

// Sort by Length using a lambda expression 
// (which is equivalent to a Comparison<T> delegate)
list.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));

// Write out the results
foreach (string name in list)
{
	Console.WriteLine(name);
}

// OUTPUT:
// Bob
// Eric
// David
// Alison
// Carlton

Our goal is to provide this exact same syntax, but for an IList<T>.

So how can we add this same functionality to IList<T>?

Easy! We’ll use a few extension methods. Without further ado, the code:

public static class SortExtensions
{
	//  Sorts an IList<T> in place.
	public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
	{
		ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
	}

	// Convenience method on IEnumerable<T> to allow passing of a 
	// Comparison<T> delegate to the OrderBy method.
	public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
	{
		return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
	}
}

// Wraps a generic Comparison<T> delegate in an IComparer to make it easy 
// to use a lambda expression for methods that take an IComparer or IComparer<T>
public class ComparisonComparer<T> : IComparer<T>, IComparer
{
	private readonly Comparison<T> _comparison;

	public ComparisonComparer(Comparison<T> comparison)
	{
		_comparison = comparison;
	}

	public int Compare(T x, T y)
	{
		return _comparison(x, y);
	}

	public int Compare(object o1, object o2)
	{
		return _comparison((T)o1, (T)o2);
	}
}

Breaking it down.

First things first: How can we sort an IList<T>, anyway? Fortunately, we don’t have to write our own sorting algorithm, since the .NET framework provides a way to get the job done. The ArrayList.Adapter method may be used to wrap the IList in an ArrayList, and then we can use the ArrayList’s Sort() method on the wrapped list. This will have the effect of sorting the list in-place, without needing to make an in-memory copy.

ArrayList.Adapter(ilist).Sort( ... );

Defining the IList<T>.Sort() extension method.

Since our goal is to mimic the List<T>.Sort() method, we must be able to accept a lamdba expression—in the form of a Comparison<T> delegate—into the Sort() method, like so:

public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
	// Compiler error! Comparison<T> is not an IComparer
	ArrayList.Adapter((IList)list).Sort(comparison); 
}

We’re almost there, but sadly, the extension method defined above will not compile. ArrayList.Sort() takes an IComparer, not a Comparison<T>. Our goal, however, is to accept a Comparison<T>, so how can we make that happen?

Wrapping the Comparison<T> delegate.

The answer is that we can wrap the Comparison<T> in a class implementing IComparer and IComparer<T>. We’ll call the class ComparisonComparer, since it is an IComparer that works by using a Comparison<T> delegate.

public class ComparisonComparer<T> : IComparer<T>, IComparer
{
	private readonly Comparison<T> _comparison;

	public ComparisonComparer(Comparison<T> comparison)
	{
		_comparison = comparison;
	}

	public int Compare(T x, T y)
	{
		return _comparison(x, y);
	}

	public int Compare(object o1, object o2)
	{
		return _comparison((T)o1, (T)o2);
	}
}

Now that we have our ComparisonComparer, we can complete the Sort extension:

public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
	// Now it works!
	ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison)); 
}

Bonus: Enumerable<T>.OrderBy()

List.Sort() and ArrayList.Sort() are quick and easy to use, but they are both backed by the same implementation of the QuickSort algorithm in Array.Sort, which has one potential drawback: it’s an unstable sorting algorithm. From MSDN:

[The Array.Sort] method uses the QuickSort algorithm. This implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.

The LINQ OrderBy() extension method provides an alternative way to sort a list, and utilizes a stable sorting algorithm. However, OrderBy() requires different syntax and will only accept a key selector delegate and/or an IComparer, rather than a Comparison<T>. Fortunately, the same technique that we used for IList<T> may be applied to OrderBy():

public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
{
	return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
}

This technique unifies the various sorting methods, so that whether you’re using List.Sort, IList.Sort, or IEnumerable.OrderBy, you can use the exact same syntax.

Using the new extensions.

Get the code

There you have it! These extensions unify the syntax for several disparate sorting methods built-in to the .NET Framework. Simply include the SortExtensions classes in your project, and you can use a lambda expression (or other delegate) to easily sort ILists and IEnumerables:

IList<string> iList = new []
{ 
	"Carlton", "Alison", "Bob", "Eric", "David"
};

// Use the custom extensions:

// Sort in-place
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));

// Or use OrderBy()
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));