using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; using System.Reflection; namespace GummingCommon { public static class OrderExtension { public static IOrderedQueryable OrderBy(this IQueryable source, string property) { return ApplyOrder(source, property, "OrderBy"); } public static IQueryable OrderBy(this IQueryable source, string property, string ascending) { var param = Expression.Parameter(typeof(T), "p"); var prop = Expression.Property(param, property); var exp = Expression.Lambda(prop, param); string method = (ascending.ToLower() == "asc" || ascending == "true") ? "OrderBy" : "OrderByDescending"; Type[] types = new Type[] { source.ElementType, exp.Body.Type }; var mce = Expression.Call(typeof(Queryable), method, types, source.Expression, exp); return source.Provider.CreateQuery(mce); } public static IOrderedQueryable OrderByDescending(this IQueryable source, string property) { return ApplyOrder(source, property, "OrderByDescending"); } public static IOrderedQueryable ThenBy(this IOrderedQueryable source, string property) { return ApplyOrder(source, property, "ThenBy"); } public static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, string property) { return ApplyOrder(source, property, "ThenByDescending"); } static IOrderedQueryable ApplyOrder(IQueryable source, string property, string methodName) { string[] props = property.Split('.'); Type type = typeof(T); ParameterExpression arg = Expression.Parameter(type, "x"); Expression expr = arg; foreach (string prop in props) { // use reflection (not ComponentModel) to mirror LINQ PropertyInfo pi = type.GetProperty(prop); expr = Expression.Property(expr, pi); type = pi.PropertyType; } Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type); LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg); object result = typeof(Queryable).GetMethods().Single( method => method.Name == methodName && method.IsGenericMethodDefinition && method.GetGenericArguments().Length == 2 && method.GetParameters().Length == 2) .MakeGenericMethod(typeof(T), type) .Invoke(null, new object[] { source, lambda }); return (IOrderedQueryable)result; } } }