'Нет универсального метода>' OrderByDescending 'для типа' System.Linq.Queryable 'совместим с предоставленными аргументами и аргументами типа - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь динамически использовать рефлексию для выполнения 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);
        }

1 Ответ

0 голосов
/ 09 января 2019

В случае ошибки вы указываете property.PropertyType (new Type[] { type, property.PropertyType }) в качестве аргумента универсального типа TKey вызываемого универсального метода OrderBy<TSource, TKey>, но лямбда-тип селектора (который должен соответствовать TKey) bool, следовательно, исключение.

Чтобы исправить это, измените

new Type[] { type, property.PropertyType }

до

new Type[] { type, typeof(bool) }

или более обобщенно (может использоваться в обоих методах)

new Type[] { type, orderByExpression.ReturnType  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...