如何在不使用 Invoke 方法的情况下组合两个 lambda 表达式?
Posted
技术标签:
【中文标题】如何在不使用 Invoke 方法的情况下组合两个 lambda 表达式?【英文标题】:How can I combine two lambda expressions without using Invoke method? 【发布时间】:2012-05-23 17:15:29 【问题描述】:我有两个 lambda 表达式:
Expression<Func<MyEntity, bool>> e1 = i = >i.FName.Contain("john");
和
Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contain("smith");
i 类型来自我的 poco 实体,不能与调用一起使用。我想在运行时结合这些。
我想在运行时以类似的方式组合这些表达式:
Expression<Func<MyEntity, bool>> e3 = Combine(e1,e2);
【问题讨论】:
是的,还有。我想在运行时结合这些。 【参考方案1】:问题是你不能只是“和”/“或”它们,因为你需要重写内部来改变参数;如果您使用来自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");
// rewrite e1, using the parameter from e2; "&&"
var lambda1 = Expression.Lambda<Func<MyEntity, bool>>(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<Func<MyEntity, bool>>(Expression.OrElse(
new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
e2.Body), e2.Parameters);
【讨论】:
绝妙的答案!花了两天时间尝试实现这一点,其他答案包含大量代码。非常感谢,马克!【参考方案2】:也许用一个简单的 if 语句?
using (MyDataBaseEntities db = new MyDataBaseEntities())
if (db.People.Any(p => p.FirstName == FirstNameText.Text && p.LastName == LastNameText.Text))
//Do something
【讨论】:
以上是关于如何在不使用 Invoke 方法的情况下组合两个 lambda 表达式?的主要内容,如果未能解决你的问题,请参考以下文章
在不添加FormLayout的情况下组合GridLayout和FillLayout?
如何在不引用表单的情况下使用 ISynchronizeInvoke