ave you ever wanted to use a strongly-typed collection to bind your data presentation controls to, only to find that you have very limited sorting capabilities, if any at all?
If you are trying to stick to good object-oriented design and shrink the amount of data that you keep in memory, transfer from your data source, or serialize to clients, you likely have run into this situation because you are using strongly-typed collections of your domain objects. So what do you do if you need to sort those collections for presentation or faster searching?
One common solution to the problem is to not use a collection when you need to sort the data and instead switch to using a DataSet. You can also choose to get data directly from the source already sorted and either bind directly to it (using a DataReader) or create another read-only collection. Unfortunately, this means potentially duplicating a lot of data in memory, creating greater coupling between the data and presentation tier, and increasing maintenance costs by having multiple points of contact between those tiers.
There is, thankfully, another solution, which is to make the custom collection sortable. The .NET Framework provides some functionality in this direction, but it has certain limitations. The ArrayList class supports a Sort method that has three overloadsone will sort by the IComparable implementation provided by the objects in the collection; another allows you to specify an IComparer to use for sorting, and the third overload allows the specification of an IComparer, a start index, and a count to sort only part of the list.
All three of these methods ultimately call the Array.Sort method, which has a very similar signature, and pass in the ArrayList's underlying Object array to be sorted using the specified IComparer (or Comparer.Default if none is specified). The Array.Sort method uses the QuickSort algorithm, which is widely agreed upon to be the fastest sorting algorithm since it sorts in O(N*log2N) time, which means that, on average, it will sort only to the logarithm (with a base of two) of the number of items times the number of items in the collection.
While using the QuickSort algorithm is great, the limitations of the provided framework are two-fold. First, to use this to sort a collection by one or more of the properties of its objects, you have to implement a custom IComparer for each property that you want to sort upon. Second, if you want to sort on multiple properties at once, providing IComparer implementations for each possible combination of properties would easily become ridiculously unmanageable.
For instance, an object with eight properties could have 40,320 permutations, not including varying the direction on each property sorted upon. If you multiply this by the number of different types in a particular domain, you can see how this is not a viable solution. Clearly, a different solution is necessary if you want to sort your collections, and that is where the solution in this article comes into play.
My solution uses dynamic code generation, compilation, and execution to allow users to sort a custom object collection using the familiar syntax of T-SQL. This implementation allows the user to call a Sort method on the collection, and pass in a string that specifies the sort order, e.g., using "SomeProperty1, SomeProperty3 DESC" as the sort expression.
You can download the code now and start taking advantage of this capability, but I would like to spend some time explaining how this solution is possible and what the caveats are if you go this route.
The core enabling feature of this sortable collection is the dynamic creation of IComparer implementations through the GetMultiComparer method. In short, this method builds a string containing the code required for an IComparer implementation, uses the C# compiler to compile the code, generating a new assembly in memory, and finally uses Reflection to create an instance of the IComparer from the new assembly. Let me explain each of these steps in more depth.