问题在于你不能简单地将它们“与”、“或”起来,因为你需要重新编写内部代码以更改参数。如果你使用
e1
的
.Body
,但是来自
e2
的
参数,那么它将不起作用——因为
e1
的
.Body
引用了一个完全无关的参数实例,该实例未被定义。如果你使用以下代码,则更为
明显:
Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john")
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith")
(注意e1
使用i
和e2
使用j
的区别)
如果我们在不重写参数的情况下将它们组合在一起,我们会得到无意义的结果:
Expression<Func<MyEntity, bool>> combined =
i => i.FName.Contains("john") && j.LName.Contains("smith")
(哇啊……j
是从哪里来的?)
然而,问题与参数的名称无关:它仍然是不同的参数。
由于表达式是不可变的,你无法在原地交换它。
诀窍是使用“访问者”来重写节点,像这样:
using System;
using System.Linq.Expressions;
class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
static class Program
{
static void Main()
{
Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contains("smith");
var lambda1 = Expression.Lambda<Func<MyEntity, bool>>(Expression.AndAlso(
new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
e2.Body), e2.Parameters);
var lambda2 = Expression.Lambda<Func<MyEntity, bool>>(Expression.OrElse(
new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
e2.Body), e2.Parameters);
}
}