Trouble implementing generic OrderBy solution

一曲冷凌霜 提交于 2019-12-11 06:59:46

问题


I have a method that takes IQueryable<T> and I want to implement OrderBy generically inside it. Ideally by passing in c => c.SomeProperty in as a parameter but I can't figure out how to get the generics working on that so I've tried it with a string. However I am getting the error:

Incorrect number of parameters supplied for lambda declaration

This is what I tried (using the string method)

var sortSelectorParameter = Expression.Parameter(typeof(T), "c");
var sortSelector = Expression.PropertyOrField(sortSelectorParameter, "ClientId"); // ClientId is the property string

collection = collection.OrderByDescending(Expression.Lambda<Func<T, bool>>(sortSelector));

I am very confused as OrderBy only takes one parameter - any advice?


回答1:


You need to pass the parameter to Expression::Lambda<T>, as the error says:

var sortSelectorParameter = Expression.Parameter(typeof(T), "c");
var sortSelector = Expression.PropertyOrField(sortSelectorParameter, "ClientId"); // ClientId is the property string

collection = collection.OrderByDescending(Expression.Lambda<Func<T, bool>>(sortSelector, sortSelectorParameter ));

Your "body" for the lambda refers to a parameter c, which is represented by the ExpressionParameter instance sortSelectorParameter. You need to pass this parameter instance to the lambda, so that it knows that the parameter referred to by the body is in fact the in-parameter of the lambda you wish to create.

EDIT: The above may answer your technical question, but it is unclear what you are trying to achieve here. If you just want to order by something which you know at compile-time, then you don't need any of this. What is the point of wrapping the OrderByDescending-method?

IQueryable<TElement> MySpecialOrderBy<TElement, TKey>(IQueryable<TElement> source, Expression<Func<TElement, TKey>> keySelector)
{
    return source.OrderByDescending(keySelector);
}



回答2:


It is quite complex:

private static readonly MethodInfo OrderByDescending = (from x in typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                                        where x.Name == "OrderByDescending"
                                                        let args = x.GetGenericArguments()
                                                        where args.Length == 2
                                                        let pars = x.GetParameters()
                                                        where pars.Length == 2 &&
                                                            pars[0].ParameterType == typeof(IQueryable<>).MakeGenericType(args[0]) &&
                                                            pars[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(args))
                                                        select x).Single();

public static IQueryable<T> OrderByStringDescending<T>(this IQueryable<T> query, string parameter)
{
    var par = Expression.Parameter(typeof(T), "obj");
    var selector = Expression.PropertyOrField(par, parameter);
    var lambda = Expression.Lambda(selector, par);
    return (IQueryable<T>)OrderByDescending.MakeGenericMethod(typeof(T), selector.Type).Invoke(null, new object[] { query, lambda });
}

You have to build an Expression.Lambda. The problem is that invoking the Queryable.OrderByDescending (that has two parameters, the IQueryable<> query and the Expression<>) without knowing the TKey type at compile time is complex. I solve it through reflection.




回答3:


If all you need is to pass an expression the some method that does other stuff with the collection then it's easy:

public void Test<T,TKey>(IQueryable<T> collection, Expression<Func<T,TKey>> orderByExpr)
{
    // your logic here 
    // ...
    collection = collection.OrderByDescending(orderByExpr);
}

And you call it like this:

this.Test(collection, c => c.ClientId);


来源:https://stackoverflow.com/questions/43369061/trouble-implementing-generic-orderby-solution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!