Expression經驗之一:合並LambdaExpression


有時我們會碰到這樣的狀況,就是要把兩個LambdaExpression合並起來變成一個LambdaExpression.

例如我們有如下兩個用來篩選DataRow的表達式:


Expression<Func<DataRow, bool>> exp1 = r => r["name"].ToString() == "Rose";
Expression<Func<DataRow, bool>> exp2 = r => (int)r["age"] > 20;

 

那現在我們想即根據name又根據age來篩選呢,也就是說我們想要這樣的表達式:

Expression<Func<DataRow, bool>> exp1 = r => r["name"].ToString() == "Rose" && (int)r["age"]>20;

很容易想到,可以用Expression.AndAlso來做,即

var newExp = Expression.Lambda(Expression.AndAlso(exp1.Body, exp2.Body),
Expression.Parameter(typeof (DataRow), "r"));

一切看起來很美好;p

但是接下來我們試圖去compile時就會出錯了,

 

這個錯誤就是由於兩個LambdaExpression的Body引用的是兩個不同的parameter instance,盡管parameter 的名字看起來是一樣的。關於這個錯誤這篇stackoverflow文章說的很好:http://stackoverflow.com/questions/10613514/how-can-i-combine-two-lambda-expressions-without-using-invoke-method

並且這篇文章也很出了一個基於ExpressionVisitor的解決方案,這個解決方案很棒並且切中了要點。但我覺得實現不是很直觀也,我的另一個解決方案是實現別一個ParameterReplacementVisitor。

代碼如下:

public class ParameterReplacementVisitor : ExpressionVisitor
        {
            private readonly ParameterExpression _parameter;

            public ParameterReplacementVisitor(ParameterExpression parameter)
            {
                _parameter = parameter;
            }

            public ParameterExpression Parameter
            {
                get { return _parameter; }
            }

            protected override Expression VisitParameter(ParameterExpression node)
            {
                if (node.Name == _parameter.Name)
                {
                    return _parameter;
                }

                return base.VisitParameter(node);
            }
        }

 

這樣很容易理解,並且采用的策略很簡單,就是根據Parameter Name來把parameter 統一替換成給定的parameter,問題解決。

 測試代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM