Click here to Skip to main content
15,860,972 members
Articles / Programming Languages / MSIL
Article

Dynamic List Sorting

Rate me:
Please Sign up or sign in to vote.
4.78/5 (54 votes)
14 Feb 2006CPOL6 min read 311.8K   1.8K   84   105
Dynamically sorting a list by using dynamic methods and delegates.

Introduction

This article spawned from a post on the Danish site DotNetForum.dk. The poster asked how you would go about sorting a list of, say, person objects, in a dynamic fashion like SQL. At that point, somebody mentioned the IComparer and IComparer<> interfaces and that you probably could make some sort of generic comparer using those interfaces. And a link to an article by Peter Provost named “Generic Property Comparer Class” was also provided. The article explains how to make a generic comparer using IComparer in .NET 1.1. Peter’s solution is okay considering .NET 1.1 but it’s rather bad in a .NET 2.0 context for several reasons:

  1. It only sorts one property at a time.
  2. It only sorts in ascending order.
  3. It isn’t strongly typed.
  4. It is very slow!

Note: Point 3 and 4 are just an artifact of the fact that .NET 1.1 is lacking both generics and dynamic methods.

So this made me decide that I would try to come up with a better solution utilizing the new generics in .NET 2.0 plus some other very cool features of the framework.

A key point to keep in mind when starting a project like this is performance. I mean, nobody wants to wait 5 seconds while a list gets sorted. Another key point in this project was that it should be dynamic and should, if possible, enable the user to enter a string with a SQL “Order By” like syntax, e.g., “FirstName, Age DESC, LastName”.

The Solution

The first solution I jammed out was a comparer which only used generics and was able to sort ascending as well as descending on any number of properties. So this solution met most of the important requirements. However, even though I made this before I saw Peter's 1.1 solution, they were in fact very similar except mine used generics for specifying the type of objects whereas in Peter’s solution, you pass in the item type as a parameter. Unfortunately, this solution also had the performance problem. After a few performance tests, it was clear to me that this solution was not an option.

The problem is that you can’t really fulfill the requirements without dynamically generating some amount of specific code. At least, that was the conclusion I made after a while. Fortunately, .NET 2.0 has a new feature called “dynamic methods”.

A “dynamic method” is a method you create in-memory during runtime. I won’t dive deeper into this subject but I recommend that you check it out. Basically, what I do is I compile a strongly typed version of the “Compare” method in-memory and call it using a delegate. As you will see in the next section, this is a very powerful way of getting a strongly typed method while keeping it completely dynamic and very fast.

Performance Comparison

I’ve done a few performance tests of the most commonly used sorting methods along with Peter Provost’s solution. The results are listed below:

Diagram of performance test results

Fig. 1: Sorting times for 10 to 100000 items.

As you see in fig. 1, the dynamic comparer solution is a good way of sorting your custom entity lists. The dynamic comparer is sharing the first place with the hard-coded comparer. The hard-coded comparer seems to be starting out slowly but that is just a measuring error. This clearly shows that from the runtime's perspective, the dynamic method used to sort is pretty much like the hard-coded one except that we call it through a delegate.

On the second place, we have both the weakly and the strongly typed datasets. Both of them are following the same line which is a little steeper than the other methods. That means that they are getting slower at a faster rate compared to the other methods. Some might think that the strongly typed dataset should be sorting faster than the weakly typed dataset but think again… The strongly typed dataset is just an overloaded version of the weakly typed dataset, so in fact, it is using the same sorting methods as the weakly typed version. It is also worth mentioning that populating a dataset with 10000 items or more is much slower than populating the regular lists.

Finally, on the third place, we have the generic class comparer. As you can see, it is much slower than the other methods of sorting. Not because it is badly designed or coded, but because .NET 1.1 supports neither generics nor dynamic methods.

Usage

So how do you use this comparer? Well, it’s as easy as 1-2-3:

C#
//Example:
string orderBy = "FirstName, LastName DESC"; // 1
DynamicComparer<Person> comparer = new DynamicComparer<Person>(orderBy); // 2
persons.Sort(comparer.Compare); // 3
  1. Declare a sort string or a SortProperty array. Note: This could be created and maintained by a custom editgrid.
  2. Declare an instance of the DynamicComparer class using the generic constructor.
  3. Call the sort method on the List<Person>.

That’s it!

So what’s going on behind the scenes? Let’s begin at line 2 of the previous example. At the time of instantiation of the DynamicComparer, the class will first parse the input string into a SortProperty array. These SortProperties will then be validated against the type we specified when instantiating the DynamicComparer, in this case, “Person”. This validation checks if the Person class is public, if it has any public properties named “FirstName” and “LastName”, if these properties are readable, and finally, if these properties are of a type that implements the IComparable interface. If any of these validations fail, the class will throw an exception. If the validation succeeds, the class will then generate a dynamic method using the specified SortPropertyies and instantiate an internal delegate pointing to the method. The “Compare” method on the DynamicComparer will then in turn be able to invoke this delegate when called. This means that the comparer is ready for use.

Note: If you want to change the sorting of an instance of the DynamicComparer, you can call the “Initialize” method on the instance and pass in a new ORDER BY string or a SortProperty array.

At the next step, we call the “Sort” method on the “persons” list passing in a reference to the comparer.Compare method.

Conclusion

The dynamic comparer seems to be a very efficient way of getting a flexible comparer while keeping it fast, and I’ve yet to see a better or even just a different solution that has the same flexibility and performance. Still, a couple of things could be improved in the comparer but mostly in the instantiation process. I leave it to you to come up with new suggestions and ideas to improve the comparer. I'm looking forward for your feedback!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer Jubii A/S
Denmark Denmark
Johannes Hansen was born in denmark during a thunderstorm in mid-june 1980.

He grew up stealing time on his father's C64 and finally got his own computer in 1995.

He currently work as a developer/ at the danish company Jubii A/S where he spends his time developing spam filters, portals and oher user-driven solutions using C#.

Comments and Discussions

 
Questionthe download fail Pin
xrf_mail6-Aug-15 23:03
xrf_mail6-Aug-15 23:03 
Generalgood Pin
xrf_mail6-Aug-15 22:38
xrf_mail6-Aug-15 22:38 
GeneralThanks Pin
Jon Cunningham26-Nov-11 4:43
Jon Cunningham26-Nov-11 4:43 
GeneralMy vote of 5 Pin
SBaghestani27-Jun-10 1:38
SBaghestani27-Jun-10 1:38 
GeneralIt Works in Vb.net as well but... Pin
Oslec2-Dec-08 16:22
Oslec2-Dec-08 16:22 
AnswerRe: It Works in Vb.net as well but... Pin
Johannes Hansen2-Dec-08 20:23
Johannes Hansen2-Dec-08 20:23 
Questionnull string problem Pin
ColinBashBash29-Sep-08 10:03
ColinBashBash29-Sep-08 10:03 
AnswerRe: null string problem [modified] Pin
Johannes Hansen2-Oct-08 17:42
Johannes Hansen2-Oct-08 17:42 
GeneralRe: null string problem Pin
ColinBashBash3-Oct-08 3:33
ColinBashBash3-Oct-08 3:33 
Questioncan this order propertys from composite classes? Pin
cottsak10-Apr-08 16:49
cottsak10-Apr-08 16:49 
GeneralRe: can this order propertys from composite classes? Pin
Johannes Hansen10-Apr-08 21:17
Johannes Hansen10-Apr-08 21:17 
GeneralGet an error when adding many sorting items ... Pin
zhucalvin14-Jan-08 11:12
zhucalvin14-Jan-08 11:12 
GeneralRe: Get an error when adding many sorting items ... Pin
Marc Brooks14-Jan-08 15:00
Marc Brooks14-Jan-08 15:00 
GeneralThanks! Pin
vtsantos2-Nov-07 9:21
vtsantos2-Nov-07 9:21 
GeneralSorting on properties of properties Pin
ngruson17-Aug-07 4:23
ngruson17-Aug-07 4:23 
GeneralRe: Sorting on properties of properties Pin
Johannes Hansen17-Aug-07 19:03
Johannes Hansen17-Aug-07 19:03 
QuestionCompare enum type Pin
qsupastar18-Jun-07 10:25
qsupastar18-Jun-07 10:25 
AnswerRe: Compare enum type Pin
Johannes Hansen18-Jun-07 16:00
Johannes Hansen18-Jun-07 16:00 
QuestionFiltering ? Pin
AcidBUG13-Apr-07 15:30
AcidBUG13-Apr-07 15:30 
GeneralDynamicComparer step aside for the mighty Linq project. All hail the Linq! Pin
Johannes Hansen9-Apr-07 19:53
Johannes Hansen9-Apr-07 19:53 
GeneralRe: DynamicComparer step aside for the mighty Linq project. All hail the Linq! Pin
Simone Busoli25-Apr-07 0:32
Simone Busoli25-Apr-07 0:32 
GeneralNull Check Pin
Terrance A. Snyder19-Mar-07 7:28
Terrance A. Snyder19-Mar-07 7:28 
Questionhow to use with a GridView? Pin
braditude7-Feb-07 11:11
braditude7-Feb-07 11:11 
GeneralNullReferenceException when sorting on a string Pin
Troye Stonich30-Dec-06 13:46
Troye Stonich30-Dec-06 13:46 
GeneralRe: NullReferenceException when sorting on a string Pin
Johannes Hansen1-Jan-07 0:46
Johannes Hansen1-Jan-07 0:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.