向Linq表达式添加方法调用,同时保留完整的表达式 [英] Adding a method call to a Linq Expression whilst remaining an full expression
问题描述
我如何在扩展linq表达式的同时保留它的表达式?我已经简化了很多(以避免粘贴页面)-例如,我使用Queryable而不是Enumerable,但是解决此问题的方法就足够了,最终我需要在添加方法调用的同时将其保留为表达式.
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.
例如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但不能不同时保留两个表达式和最终结果一个表达式,就可以做到这一点.
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.
推荐答案
首先,您不需要将所有内容都切换到IEnumerable
:AsQueryable()
将让您将测试集合与表达式树一起使用:
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]);
我们使用filterExp.Body
提取list.Take(2)
作为OrderByDescending
的第一个参数,然后将filterExp
参数移至lambda表达式.
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
}
这篇关于向Linq表达式添加方法调用,同时保留完整的表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!