2010-03-01 106 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