Изменение части кода в выражения - PullRequest
4 голосов
/ 09 сентября 2011

Я что-то упустил, и я не совсем уверен, что, у меня нет большого опыта работы с выражениями LINQ.

Я пытаюсь преобразовать следующий фрагмент кода в выражения.

MethodInfo orderByMethod = (from method in typeof(QueryableExtensions).GetMethods()
                            where method.Name == "OrderBy" && method.GetGenericArguments().Length > 0
                            select method).First();

MethodInfo orderByGenericMethod = orderByMethod.MakeGenericMethod(new[] { queryable.ElementType });

IQueryable queryable = orderByGenericMethod.Invoke(null, new object[] { queryable, sorting.ColumnName, sorting.Direction }) as IQueryable;

Вот моя попытка.

Expression orderByMethodExpression = Expression.Call(typeof(QueryableExtensions), "OrderBy", new[] { queryable.ElementType }, 
    Expression.Constant(queryable), 
    Expression.Constant(sorting.ColumnName), 
    Expression.Constant(sorting.Direction));

IQueryable queryable = queryable.Provider.CreateQuery(orderByMethodExpression)

Соответствующий код.

SortingExpression sorting = SortingExpression.Create(arguments.SortExpression);

IQueryable queryable = enumerable.AsQueryable();

if (sorting != null)
{
    MethodInfo orderByMethod = (from method in typeof(QueryableExtensions).GetMethods()
                             where method.Name == "OrderBy" && method.GetGenericArguments().Length > 0
                             select method).First();

    MethodInfo orderByGenericMethod = orderByMethod.MakeGenericMethod(new[] { queryable.ElementType });

    queryable = orderByGenericMethod.Invoke(null, new object[] { queryable, sorting.ColumnName, sorting.Direction }) as IQueryable;
}

object[] items = Enumerable.Cast<object>(queryable).ToArray();

arguments.TotalRowCount = items.Length;

enumerable = items;

Ошибка, которую я получаю.

Нет универсального метода 'OrderBy' для типа 'Shilony.Web.UI.WebControls.QueryableExtensions', совместимого с предоставленными аргументами и аргументами типа. Аргументы типа не должны предоставляться, если метод не является универсальным.

Просто чтобы уточнить, OrderBy - это мой собственный метод расширения, вот подпись метода.

public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName, string direction) where TSource : class

Просто чтобы понять, что не так, я изменил это на

MethodInfo orderByMethod = (from method in typeof(QueryableExtensions).GetMethods()
                            where method.Name == "OrderBy" && method.GetGenericArguments().Length > 0
                            select method).First();

MethodInfo orderByGenericMethod = orderByMethod.MakeGenericMethod(new[] { queryable.ElementType });

Expression orderByMethodExpression = Expression.Call(orderByGenericMethod,
    Expression.Constant(queryable, typeof(IQueryable)),
    Expression.Constant(sorting.ColumnName, typeof(string)),
    Expression.Constant(sorting.Direction, typeof(string)));

queryable = queryable.Provider.CreateQuery(orderByMethodExpression);

И теперь я получаю эту ошибку.

Выражение типа 'System.Linq.IQueryable' нельзя использовать для параметра типа 'System.Linq.IQueryable 1[Shilony.DomainLayer.DomainObjects.Customer]' of method 'System.Linq.IQueryable 1 [Shilony.DomainLayer.DomainObjects.Customer] OrderBy [Customer] (System.Linq .IQueryable`1 [Shilony.DomainLayer.DomainObjects.Customer], System.String, System.String) '

Я не понимаю, когда я вызываю его с теми же аргументами, это работает, но когда я пытаюсь превратить все это в выражение, оно терпит неудачу.

Ответы [ 2 ]

3 голосов
/ 10 сентября 2011

Не берите в голову, я понял это, я должен был бы более тщательно изучить детали.

Прежде, чем я сделал вызов Expression.Call дерево выражений выглядит следующим образом.

{System.Linq.IQueryable`1 [Shilony.DomainLayer.DomainObjects.Customer] OrderBy [Клиент] ( System.Linq.IQueryable, System.String, System.String )}

После того, как я сделал вызов Expression.Call, выражение превращается в следующее.

{System.Collections.Generic.List`1 [Shilony.DomainLayer.DomainObjects.Customer] .OrderBy ("LastName", null)}

Проблема и моя ошибка в том, что я попытался передать CreateQuery выражение, которое было получено в результате вызова.

Возвращаемый тип является списком, и поскольку OrderBy является методом расширения IQueryable, метод существует там, поэтому он пытается вызвать его снова, проблема не получается, потому что теперь OrderBy должен вызываться с другим количеством аргументов System.Linq.IQueryable должен быть исключен, и из-за этого он генерирует следующее исключение.

Нет универсального метода 'OrderBy' для типа 'Shilony.Web.UI.WebControls.QueryableExtensions', совместимого с предоставленными аргументами и аргументами типа.Аргументы типа не должны предоставляться, если метод не является универсальным.

Вот решение.

Expression orderByExtensionMethodExpression = Expression.Call(typeof(QueryableExtensions), "OrderBy", new[] { queryable.ElementType },
                        Expression.Constant(queryable), 
                        Expression.Constant(sorting.ColumnName), 
                        Expression.Constant(sorting.Direction, typeof(string)));

                    queryable = Expression.Lambda(orderByExtensionMethodExpression).Compile().DynamicInvoke() as IQueryable;
0 голосов
/ 09 сентября 2011

Вам не нужно вручную создавать дерево выражений. Вы можете заставить компилятор сделать это для вас более понятным способом. Это облегчит чтение и обслуживание.

Expression<Func<string, string, IOrderedQueryable<T>>> GetOrderByExpression<T>(IQueryable<T> query)
{
    //the compiler will compile the anonymous method into an expression tree
    Expression<Func<string, string, IOrderedQueryable<T>>> orderByMethodExpression = (string column, string direction) => query.OrderBy(column, direction);
    //return the expression
    return orderByMethodExpression;
}
...