4

Possible Duplicate:
Dynamic LINQ OrderBy

I have a list of custom sort options that are passed to the server from a client-side grid control (KendoUI grid if you're wondering). These sort options have the property to sort by as a string. I wrote a switch method that will check the values of the sort object and apply the appropriate LINQ.

    private IQueryable<Report> SortReports(IQueryable<Report> reports, KendoSort sort)
    {
        switch (sort.Field)
        {
            case "name":
                return sort.Dir == "asc" ? reports.OrderBy(x => x.Name) : reports.OrderByDescending(x => x.Name);
            case "description":
                return sort.Dir == "asc" ? reports.OrderBy(x => x.Description) : reports.OrderByDescending(x => x.Description);
            default:
                return sort.Dir == "asc" ? reports.OrderBy(x => x.Id) : reports.OrderByDescending(x => x.Id);
        }
    }

This is working fine but seems so ugly. How might I do this with reflection so that I don't have to write a custom function for every type of entity I want to do this with? It would be nice if I could just have a single function that did this no matter what the entity.

Community
  • 1
  • 1
CatDadCode
  • 58,507
  • 61
  • 212
  • 318

4 Answers4

2

You could use Dynamic LINQ. Here's a blog post about it from Scott Gu.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Great solution as well. I'm not sure which one I like more! – CatDadCode Oct 22 '12 at 05:57
  • You just made my life so much easier. Doing this in the repository method: `foreach (var sort in kendoSorts) reports = reports.OrderBy(string.Format("{0} {1}", sort.Field, sort.Dir));` The foreach allows it to handle multiple sortings. – CatDadCode Oct 22 '12 at 06:13
1

Marc Gravell has a great little library called FastMember. You can use it like this:

private IQueryable<Report> SortReports(IQueryable<Report> reports,KendoSort sort)
{
    var accessor = TypeAccessor.Create(typeof(Report));
    return sort.Dir == "asc" ? 
        reports.OrderBy(x => accessor[x,sort.Field]) : 
        reports.OrderByDescending(x => accessor[x,sort.Field]));
}
Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
1

Using Reflection, where KendoSort.Property is the PropertyInfo of the Report property that returns the value needed for sorting.

private IQueryable<Report> SortReports(IQueryable<Report> reports, KendoSort sort)
{
    return sort.Dir == "asc" ? reports.OrderBy(x => sort.Property.GetValue(x)) : reports.OrderByDescending(x => sort.Property.GetValue(x));
}

But then, reflection is relatively slow. Other solutions are probably better.

LightStriker
  • 19,738
  • 3
  • 23
  • 27
1

The following should create the sort function you want dynamically.

ParameterExpression pe = Expression.Parameter(typeof(Report), "x");
LambdaExpression le = Expression.Lambda(
    Expression.PropertyOrField(pe, sort.Field),
    new List<ParameterExpression>() {pe});

var leCompiled = (Func<Report, string>)le.Compile();                

return sort.Dir == "asc" ? reports.OrderBy(leCompiled) : reports.OrderByDescending(leCompiled);

It creates a Func delegate in the form x => x.ReportProperty, where ReportProperty is the value of sort.Field.

WarrenG
  • 3,084
  • 16
  • 10