将一段代码改成表达式

发布于 2024-12-03 16:42:41 字数 3413 浏览 0 评论 0原文

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

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

I'm missing something and I'm not quite sure what, I don't have a lot of experience with LINQ expressions.

I'm trying to change the following piece of code into expressions.

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;

Here is my attempt.

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)

The relevant code.

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;

The error I get.

No generic method 'OrderBy' on type 'Shilony.Web.UI.WebControls.QueryableExtensions' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.

Just to clarify OrderBy is my own extension method here is the signature of the method.

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

Just to understand what's wrong I changed it to this.

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

And now I get this error.

Expression of type 'System.Linq.IQueryable' cannot be used for parameter of type '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)'

I don't get it, when I invoke it with the same args it works but when I try to turn it all into an expression it fails.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

红焚 2024-12-10 16:42:42

没关系,我已经弄清楚了,我应该更仔细地研究细节。

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

Never mind I figured it out, I should have looked more carefully into the details.

Before I made the call to Expression.Call the expression tree is looking like this.

{System.Linq.IQueryable`1[Shilony.DomainLayer.DomainObjects.Customer] OrderBy[Customer](System.Linq.IQueryable, System.String, System.String)}

After I made the call to Expression.Call the expression turns into the following.

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

The problem and my mistake is that I tried to pass CreateQuery the expression that was resulted from the call.

The returned type is a list and because OrderBy is an extension method of IQueryable the method exists there, so it tries to call it again, the problem it fails is because now OrderBy should be called with different amount of arguments System.Linq.IQueryable should be excluded and because of that it throws the following exception.

No generic method 'OrderBy' on type 'Shilony.Web.UI.WebControls.QueryableExtensions' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.

Here is the solution.

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;
花开半夏魅人心 2024-12-10 16:42:42

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

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

You don't need to manually create an expression tree. You can get the compiler to do it for you in a much clearer way. This will make it easier to read and maintain.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文