我如何扩展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,我可以这样做,但不能保持两个表达式和结果都是表达式。
答案 0 :(得分:3)
首先,您无需将所有内容都切换为IEnumerable
:AsQueryable()
可让您将表达式树的测试集合用于:
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
}