如何在不使用Invoke方法的情况下组合两个lambda表达式?

我有两个lambda表达式:

Expression<Func> e1 = i=>i.FName.Contain("john");

 Expression<Func> e2=i=>i.LName.Contain("smith"); 

i类型,来自我的poco实体,不能与invoke一起使用。 我想在运行时结合这些。

我想在运行时以类似的方式组合这些表达式:

 Expression<Func> e3 = Combine(e1,e2); 

问题是你不能只是“和”/“或”它们,因为你需要重新编写内部来改变参数; 如果您使用来自e1.Body ,但来自e2参数 ,它将无法工作 – 因为e1.Body引用了一个完全不相关的未定义的参数实例。 如果您使用以下内容,则更为明显

 Expression> e1 = i => i.FName.Contains("john"); Expression> e2 = j => j.LName.Contains("smith"); 

(注意使用ie2使用j e1之间的差异)

如果我们在不重写参数的情况下组合它们,我们就会得到荒谬的:

 Expression> 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> e1 = i => i.FName.Contains("john"); Expression> e2 = i => i.LName.Contains("smith"); // rewrite e1, using the parameter from e2; "&&" var lambda1 = Expression.Lambda>(Expression.AndAlso( new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body), e2.Body), e2.Parameters); // rewrite e1, using the parameter from e2; "||" var lambda2 = Expression.Lambda>(Expression.OrElse( new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body), e2.Body), e2.Parameters); } }