C# Can';在可查询项上找不到OrderBy,请使用;提供的参数";。
我想使用一种方法对列表进行排序:C# Can';在可查询项上找不到OrderBy,请使用;提供的参数";。,c#,linq,expression-trees,C#,Linq,Expression Trees,我想使用一种方法对列表进行排序: private static IQueryable<T> BuildQuery<T>(IQueryable<T> query, string methodName, Expression<Func<T, object>> prop
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);
}
有人能看到我遗漏了什么吗
编辑:
我尝试了另一个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);
}
private静态IQueryable构建查询(IQueryable查询、字符串方法名、表达式属性Expression)
{
var methodCall=Expression.Call(query.Expression,
方法名,
新[]{query.ElementType,property.Body.Type},
新[]{propertyExpression});
返回query.Provider.CreateQuery(methodCall);
}
由于您希望属性选择器表达式动态地进行适当的调用,因此必须为其创建新的表达式。您不能按原样使用提供的选择器,因为它当前已键入Expression
,并且未返回您的特定类型Expression
。您可以通过将调用的类型参数更改为acceptobject
来编译它,但它不会按预期工作,因为它将进行对象引用比较(并且您的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);
}
私有静态IQueryable构建查询(
可查询的查询,
字符串methodName,
表达式(属性)
{
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(
类型(可查询),
方法名,
typeArgs,
query.Expression,
类型属性);
返回query.Provider.CreateQuery(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);
}
私有静态IQueryable构建查询(
可查询的查询,
字符串methodName,
表达式(属性)
{
var typeArguments=property.Type.GetGenericArguments();
var methodCall=Expression.Call(
类型(可查询),
方法名,
类型参数,
query.Expression,
财产);
返回query.Provider.CreateQuery(methodCall);
}
请给我看一下我先前存在的查询的构造好吗?我在方法调用上方添加了它。就是这样。你说的很有道理。我粘贴了你的代码,测试开始运行。谢谢你的回答。我添加了另一个替代方法来重新创建表达式。严格来说,不必只将源代码设置为泛型,您可以将这两种类型都设置为泛型。您的选择将对其他类型有好处,而且它肯定会使函数更加灵活。但不幸的是,我无法将属性类型设置为泛型,因为直到运行时我才知道该类型。啊,好的。我猜这意味着你要动态地生成属性选择器。如果您总是在编译时知道表达式,那么这仍然是一个很好的补充。
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);
}