c# - 在 "supplied arguments"的 Queryable 上找不到 OrderBy。

标签 c# linq expression-trees

我有一个方法可以用来对列表进行排序:

private static IQueryable<T> BuildQuery<T>(IQueryable<T> query, 
                                           string methodName, 
                                           Expression<Func<T, object>> property)             
    {
        var typeArgs = new[] { query.ElementType, property.Body.Type };

        methodCall = Expression.Call(typeof (Queryable),
                                                  methodName,
                                                  typeArgs,
                                                  query.Expression,
                                                  property);

        return query.Provider.CreateQuery<T>(methodCall);
    }

当我使用以下参数执行代码时出现异常:

var myPreExistingQuery = new List<SomeType>{ new SomeType() }.AsQueryable();
var query = BuildQuery(myPreExistingQuery, "OrderBy", x => x.SomeProperty);

异常(exception)情况是:

No method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied arguments.

谁能看到我在这里遗漏了什么?

编辑:

我尝试了 Expression.Call() 的另一个重载并得到了同样的异常:

private static IQueryable<T> BuildQuery<T>(IQueryable<T> query, string methodName, Expression<Func<T, object>> propertyExpression)             
    {
        var methodCall = Expression.Call(query.Expression,
                                         methodName,
                                         new[] {query.ElementType, property.Body.Type},
                                         new[] {propertyExpression});

        return query.Provider.CreateQuery<T>(methodCall);
    }

最佳答案

由于您希望属性选择器表达式动态地进行适当的调用,因此您必须为其创建一个新表达式。您不能按原样使用提供的选择器,因为它当前输入的是 Expression<Func<T, object>>并且不返回您的特定类型 Expression<Func<T, SomeType>> .您可以通过将调用的类型参数更改为接受 object 来使其编译。但它不会按预期工作,因为它将进行对象引用比较(并且您的 LINQ 提供程序可能无论如何都会拒绝它)。

要重新创建您的选择器表达式,您可以这样做:

private static IQueryable<T> BuildQuery<T>(
    IQueryable<T> query,
    string methodName,
    Expression<Func<T, object>> property)
{
    var typeArgs = new[] { query.ElementType, property.Body.Type };
    var delegateType = typeof(Func<,>).MakeGenericType(typeArgs);
    var typedProperty = Expression.Lambda(delegateType, property.Body, property.Parameters);

    var methodCall = Expression.Call(
        typeof(Queryable),
        methodName,
        typeArgs,
        query.Expression,
        typedProperty);

    return query.Provider.CreateQuery<T>(methodCall);
}

一个很好的替代方法是使属性类型也通用。这样,您将从一开始就获得适当的强类型选择器。

private static IQueryable<TSource> BuildQuery<TSource, TProperty>(
    IQueryable<TSource> query,
    string methodName,
    Expression<Func<TSource, TProperty>> property)
{
    var typeArguments = property.Type.GetGenericArguments();

    var methodCall = Expression.Call(
        typeof(Queryable),
        methodName,
        typeArguments,
        query.Expression,
        property);

    return query.Provider.CreateQuery<TSource>(methodCall);
}

关于c# - 在 "supplied arguments"的 Queryable 上找不到 OrderBy。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6892605/

相关文章:

c# - 有人可以解释一下 Child.Measure(availableSize) 在 silverlight 中的作用吗?

c# - 将额外参数传递给委托(delegate)

c# - 如何使用 Expression<Func> 设置嵌套属性?

c# - 将锯齿状数组的值克隆到第二个数组中的极快方法?

c# - 试图从 sql 表中删除值中的空格

c# - Linq Group By 两个可能不同或相同的属性

c# - Linq 从字符串排序方向

c# - LINQ To SQL、C#、MVC 4、模型助手中的连接问题

linq - 如何从 Expression<Func<DomainType>> 谓词转换为 Expression<Func<DTOtype> 谓词

c# - 组合 Func<bool> 表达式