3

I have a method for sorting generic lists by the object fields:

public static IQueryable<T> SortTable<T>(IQueryable<T> q, string sortfield, bool ascending)
{
    var p = Expression.Parameter(typeof(T), "p");

    if (typeof(T).GetProperty(sortfield).PropertyType == typeof(int?))
    {
        var x = Expression.Lambda<Func<T, int?>>(Expression.Property(p, sortfield), p);
        if (ascending)
            q = q.OrderBy(x);
        else
            q = q.OrderByDescending(x);
    }
    else if (typeof(T).GetProperty(sortfield).PropertyType == typeof(int))
    {
        var x = Expression.Lambda<Func<T, int>>(Expression.Property(p, sortfield), p);
        if (ascending)
            q = q.OrderBy(x);
        else
            q = q.OrderByDescending(x);
    }
    else if (typeof(T).GetProperty(sortfield).PropertyType == typeof(DateTime))
    {
        var x = Expression.Lambda<Func<T, DateTime>>(Expression.Property(p, sortfield), p);
        if (ascending)
            q = q.OrderBy(x);
        else
            q = q.OrderByDescending(x);
    }
    // many more for every type
    return q;
}

Is there any way I can collapse those ifs to a single generic statement? The main problem is that for the part Expression.Lambda<Func<T, int>> I am not sure how to write it generically.

dtb
  • 198,715
  • 31
  • 379
  • 417
Andrey
  • 1,278
  • 11
  • 30

2 Answers2

3

If you expand Queryable.OrderBy to its definition then you don't have to use the generic overload of Expression.Lambda:

public static IQueryable<T> SortTable<T>(
    IQueryable<T> q, string sortfield, bool ascending)
{
    var p = Expression.Parameter(typeof(T), "p");
    var x = Expression.Lambda(Expression.Property(p, sortfield), p);

    return q.Provider.CreateQuery<T>(
               Expression.Call(typeof(Queryable),
                               ascending ? "OrderBy" : "OrderByDescending",
                               new Type[] { q.ElementType, x.Body.Type },
                               q.Expression,
                               x));
}
dtb
  • 198,715
  • 31
  • 379
  • 417
0

Won't this work?

    public static IQueryable<T> SortTable<T>(IQueryable<T> q, string sortfield, bool ascending)
    {
        var type = typeof(T).GetProperty(sortfield).PropertyType;
        var p = Expression.Parameter(typeof(T), "p");
        var x = Expression.Lambda<Func<T, type> >(Expression.Property(p, sortfield), p);
        if (ascending)
            q = q.OrderBy(x);
        else
            q = q.OrderByDescending(x);
        return q;
    }
Nayan
  • 2,886
  • 22
  • 34
  • `type` is not a type variable (like `T`), so this won't work. – dtb Apr 15 '10 at 15:54
  • There is a method in System.Reflection that can return the `Func` type, however, I beleieve... – Noldorin Apr 15 '10 at 15:55
  • @Noldorin: Do you mean `typeof(Func).MakeGenericType(typeof(T), type)`? But then you still cannot use the result to invoke `Expression.Lambda` without reflection. – dtb Apr 15 '10 at 15:56
  • I am still on .NET 2.0 =D. Thanks guys! – Nayan Apr 15 '10 at 15:58