Click here to Skip to main content
11,417,390 members (54,419 online)
Click here to Skip to main content

Dynamic List Sorting

, 14 Feb 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
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:

//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)

Share

About the Author

Johannes Hansen
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

 
GeneralWorth Reading Pin
bilal7869917-Mar-13 23:06
memberbilal7869917-Mar-13 23:06 
GeneralThanks Pin
Jon Cunningham26-Nov-11 5:43
memberJon Cunningham26-Nov-11 5:43 
GeneralMy vote of 5 Pin
SBaghestani27-Jun-10 2:38
memberSBaghestani27-Jun-10 2:38 
GeneralIt Works in Vb.net as well but... Pin
Oslec2-Dec-08 17:22
memberOslec2-Dec-08 17:22 
AnswerRe: It Works in Vb.net as well but... Pin
Johannes Hansen2-Dec-08 21:23
memberJohannes Hansen2-Dec-08 21:23 
Questionnull string problem Pin
ColinBashBash29-Sep-08 11:03
memberColinBashBash29-Sep-08 11:03 
AnswerRe: null string problem [modified] Pin
Johannes Hansen2-Oct-08 18:42
memberJohannes Hansen2-Oct-08 18:42 
GeneralRe: null string problem Pin
ColinBashBash3-Oct-08 4:33
memberColinBashBash3-Oct-08 4:33 
Questioncan this order propertys from composite classes? Pin
cottsak10-Apr-08 17:49
membercottsak10-Apr-08 17:49 
GeneralRe: can this order propertys from composite classes? Pin
Johannes Hansen10-Apr-08 22:17
memberJohannes Hansen10-Apr-08 22:17 
GeneralGet an error when adding many sorting items ... Pin
zhucalvin14-Jan-08 12:12
memberzhucalvin14-Jan-08 12:12 
Hi everyone,

I have implemented the coding on my application. Everything is good except I got an error when adding 6 more sorting items:

====================================================================
Illegal one-byte branch at position: 4. Requested branch was: 207.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NotSupportedException: Illegal one-byte branch at position: 4. Requested branch was: 207.

Source Error:


Line 51: CheckSortProperties(sortProperties);
Line 52: method = CreateDynamicCompareMethod(sortProperties);
Line 53: comparer = (CompareMethodInvoker)method.CreateDelegate(typeof(CompareMethodInvoker));
Line 54: }
Line 55:
=====================================================================

I didn't get the updated version yet. What I implemented is the verion attached on this article. Can anybody send me a email with the updated version, please? zhucalvin@yahoo.com
I do appreciate it if anybody can help me out.

Thanks.

- Calvin
GeneralRe: Get an error when adding many sorting items ... Pin
Marc Brooks14-Jan-08 16:00
memberMarc Brooks14-Jan-08 16:00 
GeneralThanks! Pin
vtsantos2-Nov-07 10:21
membervtsantos2-Nov-07 10:21 
GeneralSorting on properties of properties Pin
ngruson17-Aug-07 5:23
memberngruson17-Aug-07 5:23 
GeneralRe: Sorting on properties of properties Pin
Johannes Hansen17-Aug-07 20:03
memberJohannes Hansen17-Aug-07 20:03 
QuestionCompare enum type Pin
qsupastar18-Jun-07 11:25
memberqsupastar18-Jun-07 11:25 
AnswerRe: Compare enum type Pin
Johannes Hansen18-Jun-07 17:00
memberJohannes Hansen18-Jun-07 17:00 
QuestionFiltering ? Pin
AcidBUG13-Apr-07 16:30
memberAcidBUG13-Apr-07 16:30 
GeneralDynamicComparer step aside for the mighty Linq project. All hail the Linq! Pin
Johannes Hansen9-Apr-07 20:53
memberJohannes Hansen9-Apr-07 20:53 
GeneralRe: DynamicComparer step aside for the mighty Linq project. All hail the Linq! Pin
Simone Busoli25-Apr-07 1:32
memberSimone Busoli25-Apr-07 1:32 
GeneralNull Check Pin
Terrance A. Snyder19-Mar-07 8:28
memberTerrance A. Snyder19-Mar-07 8:28 
Questionhow to use with a GridView? Pin
braditude7-Feb-07 12:11
memberbraditude7-Feb-07 12:11 
GeneralNullReferenceException when sorting on a string Pin
Troye Stonich30-Dec-06 14:46
memberTroye Stonich30-Dec-06 14:46 
GeneralRe: NullReferenceException when sorting on a string Pin
Johannes Hansen1-Jan-07 1:46
memberJohannes Hansen1-Jan-07 1:46 
QuestionUnique filter Pin
mac24nzmac24nz18-Oct-06 5:22
membermac24nzmac24nz18-Oct-06 5:22 
QuestionRe: Unique filter Pin
Johannes Hansen20-Oct-06 0:20
memberJohannes Hansen20-Oct-06 0:20 
AnswerDistinct Pin
mac24nzmac24nz20-Oct-06 1:26
membermac24nzmac24nz20-Oct-06 1:26 
NewsStatus... Pin
Johannes Hansen21-Sep-06 0:14
memberJohannes Hansen21-Sep-06 0:14 
GeneralRe: Status... Pin
Manuel Abadia2-Oct-06 12:45
memberManuel Abadia2-Oct-06 12:45 
AnswerRe: Status... Pin
Johannes Hansen3-Oct-06 23:07
memberJohannes Hansen3-Oct-06 23:07 
GeneralRe: Status... Pin
ebdrup12-Nov-06 4:35
memberebdrup12-Nov-06 4:35 
GeneralSorting on a string field Pin
midavis910-Aug-06 11:04
membermidavis910-Aug-06 11:04 
QuestionRe: Sorting on a string field Pin
Johannes Hansen13-Aug-06 23:39
memberJohannes Hansen13-Aug-06 23:39 
AnswerRe: Sorting on a string field Pin
midavis915-Aug-06 4:13
membermidavis915-Aug-06 4:13 
AnswerRe: Sorting on a string field Pin
Johannes Hansen15-Aug-06 4:47
memberJohannes Hansen15-Aug-06 4:47 
GeneralRe: Sorting on a string field Pin
midavis916-Aug-06 7:30
membermidavis916-Aug-06 7:30 
AnswerRe: Sorting on a string field Pin
Johannes Hansen16-Aug-06 23:11
memberJohannes Hansen16-Aug-06 23:11 
GeneralBinarySearch, Find...etc Pin
Doncp21-Jun-06 14:07
memberDoncp21-Jun-06 14:07 
AnswerRe: BinarySearch, Find...etc Pin
Johannes Hansen6-Jul-06 3:27
memberJohannes Hansen6-Jul-06 3:27 
GeneralPerformance Question Pin
Bill Pierce14-Jun-06 13:12
memberBill Pierce14-Jun-06 13:12 
AnswerRe: Performance Question Pin
Johannes Hansen14-Jun-06 22:07
memberJohannes Hansen14-Jun-06 22:07 
GeneralUsing with Structs instead of Classes Pin
mike_oop16-May-06 15:26
membermike_oop16-May-06 15:26 
GeneralRe: Using with Structs instead of Classes Pin
Marc Brooks17-May-06 11:19
memberMarc Brooks17-May-06 11:19 
GeneralRe: Using with Structs instead of Classes Pin
Marc Brooks17-May-06 17:16
memberMarc Brooks17-May-06 17:16 
GeneralMore simple way Pin
HovhannisyanRobert7-Apr-06 3:40
memberHovhannisyanRobert7-Apr-06 3:40 
AnswerRe: More simple way Pin
Johannes Hansen26-Apr-06 5:49
memberJohannes Hansen26-Apr-06 5:49 
GeneralRe: More simple way Pin
HovhannisyanRobert26-Apr-06 20:16
memberHovhannisyanRobert26-Apr-06 20:16 
AnswerRe: More simple way Pin
Johannes Hansen26-Apr-06 21:28
memberJohannes Hansen26-Apr-06 21:28 
GeneralRe: More simple way Pin
HovhannisyanRobert27-Apr-06 4:39
memberHovhannisyanRobert27-Apr-06 4:39 
QuestionSorting by Enum properties? Pin
rastachimp1-Mar-06 4:36
memberrastachimp1-Mar-06 4:36 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150427.4 | Last Updated 14 Feb 2006
Article Copyright 2005 by Johannes Hansen
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid