2

I have this code which works perfectly but it doesn't seem pretty to me. i want to shorten this code as much as possible. ascending is a boolean & sort is string.

if(ascending)
    switch (sort)
    {
        case "ID":
            return lstFiltered.OrderBy(o => o.ID).ToList();
        case "Device_Name":
            return lstFiltered.OrderBy(o => o.Device_Name).ToList();
        case "ErrorType_Name":
            return lstFiltered.OrderBy(o => o.ErrorType_Name).ToList();
        case "Error_Name":
            return lstFiltered.OrderBy(o => o.Error_Name).ToList();
        case "WAIT_TIME":
            return lstFiltered.OrderBy(o => o.WAIT_TIME).ToList();
        default:
            return lstFiltered;
    }
else
    switch (sort)
    {
        case "ID":
            return lstFiltered.OrderByDescending(o => o.ID).ToList();
        case "Device_Name":
            return lstFiltered.OrderByDescending(o => o.Device_Name).ToList();
        case "ErrorType_Name":
            return lstFiltered.OrderByDescending(o => o.ErrorType_Name).ToList();
        case "Error_Name":
            return lstFiltered.OrderByDescending(o => o.Error_Name).ToList();
        case "WAIT_TIME":
            return lstFiltered.OrderByDescending(o => o.WAIT_TIME).ToList();
        default:
            return lstFiltered;
    }
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
dieKoderin
  • 1,552
  • 3
  • 19
  • 39

4 Answers4

4

use Reverse to get rid of the second switch:

// define sorted as IEnumerable<T> where T is the actual generic type of lstFiltered

switch (sort)
{
    case "ID":
        sorted = lstFiltered.OrderBy(o => o.ID);
        break;
    case "Device_Name":
        sorted = lstFiltered.OrderBy(o => o.Device_Name);
        break;
    case "ErrorType_Name":
        sorted = lstFiltered.OrderBy(o => o.ErrorType_Name);
        break;
    case "Error_Name":
        sorted = lstFiltered.OrderBy(o => o.Error_Name);
        break;
    case "WAIT_TIME":
        sorted = lstFiltered.OrderBy(o => o.WAIT_TIME);
        break;
    default:
        sorted = lstFiltered;
}

if (!ascending) // do reverse ordering
    sorted = sorted.Reverse();

return sorted.ToList();
esskar
  • 10,638
  • 3
  • 36
  • 57
2

esskar's solution with a little bit of reflection here..

var sorted = lstFiltered.OrderBy(
               o => o.GetType()
                     .GetProperty( sort )
                     .GetValue( o, null ));
if (!ascending)
    sorted = sorted.Reverse();
return sorted.ToList();
Gabe
  • 84,912
  • 12
  • 139
  • 238
bit
  • 4,407
  • 1
  • 28
  • 50
  • You beat me to it! bit is correct. You can use reflection as outlined in this post (just know it can slow things down): http://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp – Rachael Aug 06 '14 at 05:03
0

Check out ScottGu's old article - Dynamic query Library http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library

There are also few existing extensions from here How do I specify the Linq OrderBy argument dynamically?

Community
  • 1
  • 1
Vincent
  • 482
  • 8
  • 21
0

An interesting way to achieve this is via Reflection. Other answers use Reflection to get the property and then get its value once for each element, which is rather slow.

A better way is to get the property only once, and then just call its getter once for every element:

IEnumerable<T> sorted = lstFiltered;
var property = typeof(T).GetProperty(sort);
if (property != null)
    if (ascending)
        sorted = sorted.OrderBy(o => property.GetValue(o, null));
    else
        sorted = sorted.OrderByDescending(o => property.GetValue(o, null));
return sorted.ToList();

Note that this detects the use of an nonexistant property and (like the original code) does not sort the list in that case.

Even better (faster), though, is to use Reflection to create a delegate that can be passed to OrderBy:

IEnumerable<T> sorted = lstFiltered;
var property = typeof(T).GetProperty(sort);
if (property != null)
{
    var getter = (Func<T, object>)Delegate
                    .CreateDelegate(typeof(Func<T, object>),
                                    property.GetGetMethod());
    if (ascending)
        sorted = sorted.OrderBy(getter);
    else
        sorted = sorted.OrderByDescending(getter);
}
return sorted.ToList();

That only works for reference types, though. If you're going to be using value types, the easiest thing is probably to just create an expression for the OrderBy and compile it. This will take a little bit of time to compile, but will execute as fast as possible: https://stackoverflow.com/a/7265354/310574

Community
  • 1
  • 1
Gabe
  • 84,912
  • 12
  • 139
  • 238