Cannot find OrderBy on Queryable with "supplied arguments".
I have a method that I want to use to sort the list:
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); } I get an exception when I execute the code using the following arguments:
var myPreExistingQuery = new List<SomeType>{ new SomeType() }.AsQueryable(); var query = BuildQuery(myPreExistingQuery, "OrderBy", x => x.SomeProperty); The exception is:
No method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied arguments. Can anyone see what I'm missing here?
EDIT:
I tried another overload of Expression.Call () and got the same exception:
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); } Since you want your property selection expression to make appropriate calls dynamically, you must create a new expression for it. You cannot use the provided selector as is, since it is currently printed by Expression<Func<T, object>> and does not return your specific type Expression<Func<T, SomeType>> . You might want to compile it by changing the arguments of the object call method, but it will not work as expected, since it will perform comparisons of object references (and your LINQ provider will reject it anyway).
To recreate an expression for a selector, you can do this:
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); } A good alternative would also be to create a property type. Thus, from the very beginning you will get a suitable strictly typed selector.
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); }