【问题标题】:Changing a piece of code into expressions将一段代码更改为表达式
【发布时间】:2019-11-14 19:35:49
【问题描述】:

我遗漏了一些东西,我不太确定是什么,我对 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.IQueryable1[Shilony.DomainLayer.DomainObjects.Customer]' of method 'System.Linq.IQueryable1[Shilony.DomainLayer.DomainObjects.Customer] OrderBy[Customer](System.Linq) 类型的参数.IQueryable`1[Shilony.DomainLayer.DomainObjects.Customer], System.String, System.String)'

我不明白,当我使用相同的 args 调用它时它可以工作,但是当我尝试将它全部转换为表达式时它失败了。

【问题讨论】:

    标签: c# linq reflection expression invoke


    【解决方案1】:

    没关系,我想通了,我应该更仔细地研究一下细节。

    在我调用 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;
    

    【讨论】:

      【解决方案2】:

      您无需手动创建表达式树。您可以让编译器以更清晰的方式为您执行此操作。这将使其更易于阅读和维护。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多