2010-03-01 60 views
8

我怎么会去连接两个lambda表达式像theese:加入拉姆达表达式

Expression<Func<string, bool>> expr1 = a => a.Length > 100; 
Expression<Func<string, bool>> expr2 = b => b.Length < 200; 

...到表达这样的:

Expression<Func<string, bool>> expr3 = s => s.Length < 100 && s.Length < 200; 

也就是说,与AndAlso经营者加入他们。 (或任何其他运营商的事情......)

我实际上成功了一些讨厌的递归替换lambda参数,然后加入Expression.AndAlso方法。但我正在寻找更简单的东西。

例如是这样的:(这显然不工作)

Expression<Func<string, bool>> expr3 = c => expr1(a) && expr2(b); 
+0

只是想知道,你为什么不能使用表达式> expr3 = s => s.Length <100 && s.Length <200 ;? – 2010-03-01 19:05:40

+0

这是因为表达式是基于系统中的设置生成的。我实际上需要将一个表达式列表加入到一个最终表达式中。 – LaZe 2010-03-01 19:14:34

回答

2

你的“像”,如果你正在处理正常的代表会工作。 但是如果你必须使用表达式树,除了递归替换之外,我没有看到任何其他的解决方案。

在.NET 4中,您可以使用System.Linq.Expressions.ExpressionVisitor使这种递归替换更容易。对于.NET 3.5,请看下面的示例:http://msdn.microsoft.com/en-us/library/bb882521.aspx

使用ExpressionVisitor,您只需要覆盖要替换的节点类型的方法,并自动重构周围的树。

如果您正在处理与LINQ一起使用的条件,则动态组合条件的更简单的解决方案就是多次调用Where()。

+0

我刚刚检查过,ExpressionVisitor对此很好。难以等待4.0发布。 – LaZe 2010-03-02 14:44:54

1

我刚刚发现了如何使用新的Update方法在.NET 4中执行此操作。既然这是一种新方法,我想他们一定也需要它。我对此非常满意,因为.NET 3.5解决方案真的很难看。 (注:此解决方案不反正工作检查的意见。)

Expression<Func<string, bool>> expr1 = a => a.Length > 100; 
Expression<Func<string, bool>> expr2 = b => b.Length < 200; 

// This produces a new expression where the parameter b is replaced with a 
expr2 = expr2.Update(expr1.Body, expr1.Parameters); 

// So now we can join the bodies and produce a new lambda expression. 
Expression<Func<string, bool>> expr3 = Expression.Lambda<Func<string, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters); 
+0

我想你误解了Update的功能。它仅创建一个具有相同类型,名称和尾调用选项但带有不同主体和参数集的新LambdaExpression。它不会在lamdba身体内进行任何替换。 对于expr3,运行您的示例代码输出“a =>((a.Length> 100)AndAlso(a.Length> 100))”,这不是您想要的。 – Daniel 2010-03-01 19:20:08

+0

可悲的是,你是正确的丹尼尔......所以我回到了我讨厌的解决方案:-( – LaZe 2010-03-01 19:27:49

2

这不是与Expression.Invoke太糟糕了...:

var strings = (new [] { "a", "bb", "ccc", "dddd", "eeeee", "fffff" }); 
Expression<Func<string, bool>> expr1 = a => a.Length > 1; 
Expression<Func<string, bool>> expr2 = b => b.Length < 4; 

ParameterExpression p = expr1.Parameters[0]; 

var andAlso = System.Linq.Expressions.Expression.AndAlso(Expression.Invoke(expr1, p), Expression.Invoke(expr2, p)); 
var lambda = LambdaExpression.Lambda<Func<string, bool>>(andAlso, p); 
var filteredStrings = strings.AsQueryable().Where(lambda); 
+0

感谢您的建议理查德。我会研究这个想法。由于我将表达式转换为SQL(除其他外)我需要在我的系统中的几个地方支持InvokeExpression,它比我目前的解决方案更好... – LaZe 2010-03-02 08:13:17

+0

我刚刚意识到这可以帮助我解决我刚才遇到的一个问题,并完全停留在......干杯! – 2010-03-02 13:48:39