【问题标题】:Adding a method call to a Linq Expression whilst remaining an full expression在保留完整表达式的同时向 Linq 表达式添加方法调用
【发布时间】:2009-09-04 22:40:57
【问题描述】:

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

例如L

        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,我可以做到这一点,但不能同时保留表达式和最终结果。

【问题讨论】:

  • 如果有人能解释如何以编程方式构建它,它“可能”会回答同样的问题。表达式, IEnumerable>> filter = list => list.Take(2).OrderBy(p => p.Age);
  • 如果你想做逻辑列表怎么办 => list.OrderBy(p => p.Age).Take(2);

标签: linq lambda


【解决方案1】:

首先,您不需要将所有内容都切换到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的第一个参数,然后将filterExp参数移动到lambda表达式中。

我认为这是您的预期用途?

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多