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

时间:2009-09-02 12:17:56

标签: linq lambda

我如何扩展linq表达式,同时保持表达式?我已经简化了这一点(为了避免粘贴页面) - .e.g我使用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,我可以这样做,但不能保持两个表达式和结果都是表达式。

1 个答案:

答案 0 :(得分:3)

首先,您无需将所有内容都切换为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
}