添加对 Linq 表达式的方法调用,同时保留完整表达式

发布于 2024-08-03 10:22:46 字数 1134 浏览 1 评论 0原文

如何在保留 linq 表达式的同时扩展它?我已经简化了很多(以避免粘贴页面) - 例如,我使用 Queryable 而不是 Enumerable,但是这个解决方案就足够了,最终我需要将其保留为表达式,同时添加方法调用。

例如,

        var p1 = new Person() {Name = "RDA1", Age = 27};
        var p2 = new Person() {Name = "RDA2", Age = 28};
        var p3 = new Person() {Name = "RDA3", Age = 29};

        var people = new[] {p1, p2, p3};


        Expression<Func<IEnumerable<Person>, IEnumerable<Person>>> filterExp
            = list => list.Take(2);


        Expression<Func<Person, int>> sortExp = l => l.Age;


        MethodCallExpression orderByCallExpression = Expression.Call(
            typeof (Enumerable),
            "OrderByDescending",
            new Type[] {typeof (Person), typeof (int)},
            filterExp.Parameters[0],
            sortExp); 

var combinedExpression = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>
(filterExp.AddMethodCall(orderByCallExpression)); // made up AddMethodCall but you get the idea

过去几个小时我搜索了几十个SO帖子,但我似乎无法弄清楚这一点, 如果我编译filterExp,但不保留表达式和最终结果表达式,我就可以做到这一点。

How I do extend an linq expression whilst keeping it an expression? I've simplified this quite a bit (to avoid pasting pages) - .e.g I working with Queryable rather than Enumerable, but the solution for this will suffice, ultimately I need to keep it as an expression whilst adding a method call to it.

For exampleL

        var p1 = new Person() {Name = "RDA1", Age = 27};
        var p2 = new Person() {Name = "RDA2", Age = 28};
        var p3 = new Person() {Name = "RDA3", Age = 29};

        var people = new[] {p1, p2, p3};


        Expression<Func<IEnumerable<Person>, IEnumerable<Person>>> filterExp
            = list => list.Take(2);


        Expression<Func<Person, int>> sortExp = l => l.Age;


        MethodCallExpression orderByCallExpression = Expression.Call(
            typeof (Enumerable),
            "OrderByDescending",
            new Type[] {typeof (Person), typeof (int)},
            filterExp.Parameters[0],
            sortExp); 

var combinedExpression = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>
(filterExp.AddMethodCall(orderByCallExpression)); // made up AddMethodCall but you get the idea

I've searched dozens of SO posts for the past few hours and I can't seem to figure this out,
I can do it if I compile filterExp but not without keeping both expressions and end result an expression.

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

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

发布评论

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

评论(1

水晶透心 2024-08-10 10:22:46

首先,您不需要将所有内容都切换到 IEnumerableAsQueryable() 将允许您将测试集合与表达式树一起使用:

var p1 = new Person() { Name = "RDA1", Age = 27 };
var p2 = new Person() { Name = "RDA2", Age = 28 };
var p3 = new Person() { Name = "RDA3", Age = 29 };

var people = new[] { p1, p2, p3 }.AsQueryable();

您有了一个良好的开端,您只需要改变您正在使用的内容:

Expression<Func<IQueryable<Person>, IQueryable<Person>>> filterExp
    = list => list.Take(2);

Expression<Func<Person, int>> sortExp = l => l.Age;

MethodCallExpression orderByCallExpression = Expression.Call(
    typeof(Queryable),
    "OrderByDescending",
    new Type[] { typeof(Person), typeof(int) },
    filterExp.Body,
    sortExp);

var combinedExpression =
    Expression.Lambda<Func<IQueryable<Person>, IQueryable<Person>>>(
        orderByCallExpression, filterExp.Parameters[0]);

我们使用 filterExp.Body 提取 list.Take(2) 作为 OrderByDescending 的第一个参数code>,然后将 filterExp 参数移至 lambda 表达式。

我想这就是您的预期用途?

var compiled = combinedExpression.Compile();
var res = compiled(people);

foreach (var r in res)
{
    // Do something
}

First, you don't need to switch everything to IEnumerable: AsQueryable() will let you use your test collection with expression trees:

var p1 = new Person() { Name = "RDA1", Age = 27 };
var p2 = new Person() { Name = "RDA2", Age = 28 };
var p3 = new Person() { Name = "RDA3", Age = 29 };

var people = new[] { p1, p2, p3 }.AsQueryable();

You were off to a good start, you just need to shift around what you're using where:

Expression<Func<IQueryable<Person>, IQueryable<Person>>> filterExp
    = list => list.Take(2);

Expression<Func<Person, int>> sortExp = l => l.Age;

MethodCallExpression orderByCallExpression = Expression.Call(
    typeof(Queryable),
    "OrderByDescending",
    new Type[] { typeof(Person), typeof(int) },
    filterExp.Body,
    sortExp);

var combinedExpression =
    Expression.Lambda<Func<IQueryable<Person>, IQueryable<Person>>>(
        orderByCallExpression, filterExp.Parameters[0]);

We use filterExp.Body to extract list.Take(2) as the first parameter to OrderByDescending, then move the filterExp parameter to the lambda expression.

I assume this is your intended usage?

var compiled = combinedExpression.Compile();
var res = compiled(people);

foreach (var r in res)
{
    // Do something
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文