34

I am currently ordering a list of custom objects using the IQueryable OrderBy method as follows:

mylist.AsQueryable().OrderBy("PropertyName");

Now I am looking to sort by more than one property. Is there any way to do that?

Thanks, Yannis

Yannis
  • 6,047
  • 5
  • 43
  • 62

4 Answers4

66
OrderBy(i => i.PropertyName).ThenBy(i => i.AnotherProperty)

In OrderBy and ThenBy you have to provide keySelector function, which chooses key for sorting from object. So if you know property name only at runtime then you can make such function with Reflection like:

var propertyInfo = i.GetType().GetProperty("PropertyName"); 
var sortedList = myList.OrderBy(i => propertyInfo.GetValue(i, null)) 

But it will be slower, then direct access to property. Also you can "compile" such function on the fly with Linq.Expressions and it will work faster than reflection but it is not very easy. Or you can use CollectionViewSource and their sorting ablilities in WPF.

And don't forget that OrderBy() returns sorted enumerable and it does not sort your existed List inplace. In your example you did not save sorted list to variable.

Nikolay
  • 3,658
  • 1
  • 24
  • 25
  • Thats the thing though. The PropertyName is really a String (cause its coming in from a sorting selector). so I cant use this. Any alternatives? – Yannis Mar 21 '12 at 08:14
  • In OrderBy and ThenBy you have to provide keySelector function, which chooses key for sorting from object. With string property name you can make such function with Reflection: `var propertyInfo = i.GetType().GetProperty("PropertyName"); myList.OrderBy(i => propertyInfo.GetValue(i, null))` but it will be slower, then direct access to property. Also you can "compile" such function on the fly with Expressiosn and it will work faster than expressions but it is not very easy. Or you can use CollectionViewSource and their sorting ablilities in WPF – Nikolay Mar 21 '12 at 08:52
  • 1
    @Nikolay - Why not just use dynamic Linq instead? – Chris Gessler Mar 21 '12 at 10:37
  • 1
    Yes, you can use dynamic linq too to just get that you need. Dynamic linq itself creates expressions from string on the fly as i proposed with Linq.Expressions. And it is usually good to know how things work inside. But you are right, on this case it is better just use library – Nikolay Mar 21 '12 at 17:43
19

You could use .ThenBy:

var result = mylist
    .AsQueryable()
    .OrderBy(x => x.PropertyName)
    .ThenBy(x => x.SomeOtherProperty);
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    Thats the thing though. The PropertyName is really a String (cause its coming in from a sorting selector). so I cant use this. Any alternatives? – Yannis Mar 20 '12 at 17:02
8

You probably want to use the ThenBy extension method to be able to sort by multiple fields

 return myList.AsQueryable().OrderBy(m=>m.Property1).ThenBy(m => m.Property2);

If you want dynamic Linq, look at LinqKit. I recently implemented Microsoft's dynamic Linq library from here and was able to sort by two fields using a string.

Awesome stuff! Not sure if this will be in .NET 5 or not.

Chris Gessler
  • 22,727
  • 7
  • 57
  • 83
  • Thats the thing though. The PropertyName is really a String (cause its coming in from a sorting selector). so I cant use this. Any alternatives? – Yannis Mar 21 '12 at 08:20
1

As others have suggested, you can use 'ThenBy'. If you want to convert a string to a different value before using it, this is possible too, for example...

    var sortedSystemTestResultsList = systemTestResultsList.OrderBy(s =>
    {
        DateTime dt;
        if (!DateTime.TryParse(s.testPointCompletedDate, out dt)) return DateTime.MaxValue;
        return dt;
    }).ThenBy(s =>
    {
        Int32 tpID;
        if (!Int32.TryParse(s.testRunResultID, out tpID)) return Int32.MaxValue;
        return tpID;
    });
ZenoArrow
  • 697
  • 7
  • 21