将一段代码更改为表达式

时间:2011-09-09 02:47:23

标签: linq reflection invoke expression

我遗漏了一些东西而且我不太清楚什么,我对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;

我得到的错误。

类型'Shilony.Web.UI.WebControls.QueryableExtensions'上没有泛型方法'OrderBy'与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

为了澄清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](系统)类型的参数.Linq.IQueryable`1 [Shilony.DomainLayer.DomainObjects.Customer],System.String,System.String)'

我没有得到它,当我使用相同的args调用它时它会起作用,但是当我尝试将它全部转换为表达式时它会失败。

2 个答案:

答案 0 :(得分:3)

别介意我弄清楚了,我应该仔细研究细节。

在我调用Expression.Call之前,表达式树看起来像这样。

{System.Linq.IQueryable`1 [Shilony.DomainLayer.DomainObjects.Customer] OrderBy [Customer]( 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 ,因此会抛出以下异常。

类型'Shilony.Web.UI.WebControls.QueryableExtensions'上没有泛型方法'OrderBy'与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

以下是解决方案。

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;

答案 1 :(得分:0)

您无需手动创建表达式树。您可以让编译器以更清晰的方式为您完成。这样可以更容易阅读和维护。

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;
}