Sorting a generic list on arbitrary property (C#)

I often need to sort a generic list on some arbitrary property. After writing the code a couple of times I decided to make it more generic using generics and some reflection. Oh, I know that reflection if costly and this is not a good way to sort large lists, but I typically work with small lists.

public enum SortDirection
{
   Ascending, Descending
}

public class ListSorter where T : class
{
  public static List Sort
(
              List listToSort,
              string propertyName,
              SortDirection direction) where P : IComparable
  {
    Type propertyType = typeof (P);
    Type comparableInterface = propertyType.GetInterface("IComparable");

    if (comparableInterface == null)
        throw new Exception("Properties to sort by must be IComparable");

    listToSort.Sort(
        delegate(T x, T y)
            {
              PropertyInfo p1 = x.GetType().GetProperty(propertyName, propertyType);
              PropertyInfo p2 = y.GetType().GetProperty(propertyName, propertyType);

              object p1objvalue = p1.GetValue(x, null);
              object p2objvalue = p2.GetValue(y, null);

              P p1value = (P)p1objvalue;
              P p2value = (P)p2objvalue;

              if (direction == SortDirection.Ascending)
                  return p1value.CompareTo(p2value);
              else
                  return p2value.CompareTo(p1value);
          });

    return listToSort;
  }
}

To sort a list of Person objects by the string property FirstName do the following:

List myUnsortedList = GetPersonsInRandomOrder();
List sortedList =  ListSorter
                                     .Sort(
                                     myUnsortedList,
                                     "FirstName",
                                     SortDirection.Ascending);

To sort a list of Person objects by the int property Age do the following:

List myUnsortedList = GetPersonsInRandomOrder();
List sortedList =  ListSorter
                                     .Sort(
                                     myUnsortedList,
                                     "Age",
                                     SortDirection.Ascending);

If you have the luxury of using .NET Framework 3.0 or 3.5 you can use Linq to solve the problem really quick:


var sortedPersonList = from p in unsortedPersonList
                               orderby p.FirstName
                               select p;

foreach (var person in sortedPersonList)
{
    Console.WriteLine(person.FirstName + " " + person.LastName);
}

Leave a comment to this post if you have any thoughts.

This entry was posted in Development and tagged , , , , . Bookmark the permalink.

5 Responses to Sorting a generic list on arbitrary property (C#)

  1. Gopinath Varadharajan says:

    Hi Pal,

    You are the best! was searching for generic list sort in a simple way, and no one mentioned about Linq !

    Thanks again, it save me a big chunk of code and Thanks to Linq’s Simplicity…

    Thanks,

    Gopi

  2. Pål says:

    Yes, Linq is really handy and I use it more and more in different places I had not thought of at first.

  3. César F. Qüeb Montejo says:

    Awesome code Pal :) !!! , very, very useful.. just searching for some like this.. thank you a lot!!!

    Regards

  4. Ron Rudman says:

    This works well for properties that are ints, dates, etc. But what about for a string property where the value could contain special characters? In particular, I’m pretty sure values like “coop” and “co-op” would be sorted together by the default CompareTo for strings in this code. Short of doing some kind of ugly if-then-else in the delegate, how can this be made to use the ordinal type of string compare?

  5. Pål says:

    Good question. You’ll have to test that and let us know :)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>