Search code examples
c#.netlinqsortingexpression-trees

Sort using Linq.Expressions.Expression


I wrote this code that sorts an IQueryable<T> by the column sortColumn. I would like to extend it so that the entries that have the value of the column BirthDate equal to DateTime.Today would be placed first in the sort, but I just can't find or think of how to do the job.

public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string sortColumn, bool asc)
{
    var param = Expression.Parameter(typeof(T), "p");

    var prop = Expression.Property(param, sortColumn);

    var exp = Expression.Lambda(prop, param);

    string method = asc ? "OrderBy" : "OrderByDescending";

    Type[] types = new[] { q.ElementType, exp.Body.Type };

    var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);

    return q.Provider.CreateQuery<T>(mce);
}

Solution

  • See Handle GridView.OnSorting() and create sorting expression dynamically using LINQ

    public static class SortExpressionBuilder<T>
    {
        private static IDictionary<SortDirection, ISortExpression> directions =  new Dictionary<SortDirection, ISortExpression>
        {
            { SortDirection.Ascending, new OrderByAscendingSortExpression() },
            { SortDirection.Descending, new OrderByDescendingSortExpression() }
        };
    
        interface ISortExpression
        {
            Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> GetExpression();
        }
    
        class OrderByAscendingSortExpression : ISortExpression
        {
            public Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> GetExpression()
            {
                return (c, f) => c.OrderBy(f);
            }
        }
    
        class OrderByDescendingSortExpression : ISortExpression
        {
            public Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> GetExpression()
            {
                return (c, f) => c.OrderByDescending(f);
            }
        }
    
        public static Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> CreateExpression(SortDirection direction)
        {
            return directions[direction].GetExpression();
        }
    }
    
    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string columnName, SortDirection direction)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), "x"); // x
        Expression property = Expression.Property(param, columnName);     // x.ColumnName
        Func<T, object> func = Expression.Lambda<Func<T, object>>(        // x => x.ColumnName
           Expression.Convert(Expression.Property(param, columnName), 
           typeof(object)), param
        ).Compile();
    
        Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> expression = SortExpressionBuilder<T>.CreateExpression(direction);
        IEnumerable<T> sorted = expression(collection, func);
        return sorted;
    }
    

    And links from the bottom: