Я пытаюсь динамически использовать рефлексию для выполнения OrderBy того, является ли данный sortColumn (string) нулевым или нет, ThenBy для значения sortColumn и ThenBy для жестко закодированных столбцов. Вот так:
if (!String.IsNullOrEmpty(sortColumn)) {
var descending = sortDirection == "desc";
views = views.AsQueryable()
.OrderByNull<ToDoView>(sortColumn, true)//extension method
.OrderBy<ToDoView>(sortColumn, descending, true)//extension method
.ThenBy(v => v.summary ?? v.description).ToList();
}
Используя другие ответы SO, я смог заставить работать метод расширения OrderBy:
public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc, bool thenBy = false) {
string command = desc ? "OrderByDescending" : "OrderBy";
if (thenBy)
command = desc ? "ThenByDescending" : "ThenBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
Вот мой метод расширения OrderByNull:
public static IOrderedQueryable<TEntity> OrderByNull<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc, bool thenBy = false) {
string command = desc ? "OrderByDescending" : "OrderBy";
if (thenBy)
command = desc ? "ThenByDescending" : "ThenBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var target = Expression.Constant(null, type);
var equalsMethod = Expression.Call(Expression.Property(parameter, orderByProperty), "Equals", null, target);
var orderByExpression = Expression.Lambda(equalsMethod, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
При выполнении этого метода расширения значение orderByExpression оценивается как:
{p => p.listName.Equals(null)}
Однако при попытке установить выражение resultExpression выдает исключение:
System.InvalidOperationException: 'Нет универсального метода
'OrderByDescending' для типа 'System.Linq.Queryable' совместим с
предоставленные аргументы типа и аргументы. Никаких аргументов типа не должно быть
при условии, что метод не является универсальным. «
Я не совсем уверен, как это исправить, так как выражение выглядит мне правильно. Есть идеи?
================
Вот мой последний метод расширения OrderByNull после исправления из принятого ответа и разрешения NRE с помощью логики равенства:
public static IOrderedQueryable<TEntity> OrderByNull<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc, bool thenBy = false) {
string command = desc ? "OrderByDescending" : "OrderBy";
if (thenBy)
command = desc ? "ThenByDescending" : "ThenBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var target = Expression.Constant(null, type);
var equalsMethod = Expression.Equal(Expression.Property(parameter, orderByProperty), Expression.Constant(null, typeof(object)));
var orderByExpression = Expression.Lambda(equalsMethod, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, typeof(bool) },
source.Expression, Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}