Byr*_*ahl 8 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);
}
Run Code Online (Sandbox Code Playgroud)
当我使用以下args执行代码时出现异常:
var myPreExistingQuery = new List<SomeType>{ new SomeType() }.AsQueryable();
var query = BuildQuery(myPreExistingQuery, "OrderBy", x => x.SomeProperty);
Run Code Online (Sandbox Code Playgroud)
例外是:
No method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied arguments.
Run Code Online (Sandbox Code Playgroud)
谁能看到我在这里失踪的东西?
编辑:
我尝试了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);
}
Run Code Online (Sandbox Code Playgroud)
Jef*_*ado 11
由于您希望属性选择器表达式动态地进行适当的调用,因此必须为其创建新表达式.您不能按原样使用提供的选择器,因为它当前是键入的,Expression<Func<T, object>>而不是返回您的特定类型Expression<Func<T, SomeType>>.您可以通过将调用的类型参数更改为accept来使其编译,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);
}
Run Code Online (Sandbox Code Playgroud)
这样做的一个很好的替代方法是使属性类型也是通用的.这样,您将从一开始就获得一个适当强类型的选择器.
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);
}
Run Code Online (Sandbox Code Playgroud)