'无泛型方法 > 'System.Linq.Queryable' 类型上的 'OrderByDescending' 与提供的类型参数和参数兼容

Jus*_*tin 0 c# linq reflection

我试图动态地使用反射做一个OrderBy是否给定的sortColumn(串)为空或不是,一ThenBysortColumn价值和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();
}
Run Code Online (Sandbox Code Playgroud)

使用其他 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);
}
Run Code Online (Sandbox Code Playgroud)

这是我的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);
}
Run Code Online (Sandbox Code Playgroud)

执行此扩展方法时,orderByExpression计算结果为:

{p => p.listName.Equals(null)}
Run Code Online (Sandbox Code Playgroud)

但是,当尝试设置 时resultExpression,它会引发异常:

System.InvalidOperationException: '没有泛型方法' OrderByDescending'在类型' System.Linq.Queryable'上与提供的类型参数和参数兼容。如果方法是非通用的,则不应提供类型参数。

我不太确定如何解决这个问题,因为这个表达式对我来说是正确的。有任何想法吗?


这是我的最终OrderByNull扩展方法,在从接受的答案中修复并NullReferenceException使用 equals 逻辑解决 a 之后:

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);
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 5

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

要修复它,请更改

new Type[] { type, property.PropertyType }
Run Code Online (Sandbox Code Playgroud)

new Type[] { type, typeof(bool) }
Run Code Online (Sandbox Code Playgroud)

或更一般地(可以在两种方法中使用)

new Type[] { type, orderByExpression.ReturnType  }
Run Code Online (Sandbox Code Playgroud)