I have a fairly common requirement to enable user-defined sorting, for example using a querystring like so:
?page=2&sort=name&desc=true
This isn’t really catered for using LINQ, due to type-safety (you need to use an expression based on a property of your object to do sorting). To enable dynamic sorting on an IQueryable object, try this:
private static readonly MethodInfo OrderByMethod =
typeof(Queryable).GetMethods()
.Where(method => method.Name == "OrderBy")
.Where(method => method.GetParameters().Length == 2)
.Single();
private static readonly MethodInfo OrderByDescendingMethod =
typeof(Queryable).GetMethods()
.Where(method => method.Name == "OrderByDescending")
.Where(method => method.GetParameters().Length == 2)
.Single();
public static IQueryable DynamicOrderBy(this IQueryable source, string sortBy, bool sortDescending = false)
{
if (string.IsNullOrWhiteSpace(sortBy))
return source;
if (sortBy.Contains(','))
{
foreach (var sort in sortBy.Split(','))
{
source = source.DynamicOrderBy(sort, sortDescending);
}
return source;
}
else
{
var type = typeof(TSource);
var parameter = Expression.Parameter(type, sortBy);
var propertyRef = Expression.Property(parameter, sortBy);
var lambda = Expression.Lambda(propertyRef, new[] { parameter });
MethodInfo genericMethod = (sortDescending ? OrderByDescendingMethod : OrderByMethod)
.MakeGenericMethod(new[] { typeof(TSource), propertyRef.Type });
object ret = genericMethod.Invoke(null, new object[] { source, lambda });
return (IQueryable)ret;
}
}
Putting this in your code allows you to write something like this:
IQueryable data = GetData();
var sortedByNameDescending = data.DynamicOrderBy("Name", true);