类型'System.Linq.Queryable'上的'没有通用方法>'OrderByDescending'与提供的类型实参和实参兼容

时间:2019-01-09 15:01:14

标签: c# linq reflection

我正在尝试动态地使用反射对给定的sortColumn(字符串)是否为null进行OrderBy,对sortColumn值进行ThenBy,对硬编码列进行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:'没有通用方法   类型'System.Linq.Queryable'上的'OrderByDescending'与   提供的类型实参和实参。类型参数不应该是   如果该方法是非泛型的,则提供。 '

我不太确定如何解决此问题,因为该表达式对我而言很合适。有什么想法吗?

================

这是我最后的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 :(得分:4)

在失败的情况下,您将property.PropertyTypenew Type[] { type, property.PropertyType })指定为被调用的泛型方法TKey的{​​{1}}泛型类型参数,但是选择器lambda结果类型(应该与OrderBy<TSource, TKey>相匹配的是TKey,因此是例外。

要修复此问题,请更改

bool

new Type[] { type, property.PropertyType }

或更通用(可以在两种方法中同时使用)

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