Expression筆記-ExpressionVisitor介紹及案例


介紹:

案例1:使用已有表達式樹構建新的表達式樹

Expression<Func<string, bool>> lambda0 = item => item.Length > 2;
Expression<Func<string, bool>> lambda1 = item => item.Length < 4;

將上面兩個表達式合並成一個 item=>item.Length>&& item.Length<4 

不能直接使用下面這種方法構建新的表達式樹,因為Body中帶着之前的Parameter信息

public Func<string, bool> ReBuildExpression(Expression<Func<string, bool>> lambd0, Expression<Func<string, bool>> lambd1)
        {
            parameter = Expression.Parameter(typeof(string), "name");
            Expression left = lambd0.Body;
            Expression right = lambd1.Body;
            BinaryExpression expression = Expression.AndAlso(left, right);
            Expression<Func<string, bool>> lambda = Expression.Lambda<Func<string, bool>>(expression, parameter);
            return lambda.Compile();
        }

只能使用ExpressionVisitor修改表達式,將之前的Parameter替換成新的

public class SetParamExpressionVisitor : ExpressionVisitor
    {
        public ParameterExpression Parameter { get; set; }
        public SetParamExpressionVisitor() { }
        public SetParamExpressionVisitor(ParameterExpression parameter) {
            this.Parameter = parameter;
        }
        public Expression Modify(Expression exp)
        {
            return this.Visit(exp);
        }
        protected override Expression VisitParameter(ParameterExpression parameter)
        {
            return this.Parameter;
        }
    }
public static Func<string, bool> AndAlsoExpression(Expression<Func<string,bool>> exp1,Expression<Func<string, bool>> exp2)
        {
            var parameter = Expression.Parameter(typeof(string), "name");
            SetParamExpressionVisitor visitor = new SetParamExpressionVisitor(parameter);
            var newExp1 = visitor.Modify(exp1.Body);
            var newExp2 = visitor.Modify(exp2.Body);
            var newBodyExp = Expression.AndAlso(newExp1, newExp2);
            return Expression.Lambda<Func<string, bool>>(newBodyExp, parameter).Compile();
        }

調用:

Expression<Func<string, bool>> exp1 = item => item.Length > 2;
Expression<Func<string, bool>> exp2 = item => item.Length < 4;
Func<string,bool> func = AndAlsoExpression(exp1, exp2);
bool b = func("aaaa");//false

 有了上面的基礎,可以寫幾個擴展方法 And()、Or()、Not() 

public static class ExpressionExtension
    {
        #region Expression<Func<T>>擴展
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp1, Expression<Func<T, bool>> exp2)
        {
            return exp1.Compose(exp2, Expression.AndAlso);
        }
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp1, Expression<Func<T, bool>> exp2)
        {
            return exp1.Compose(exp2, Expression.OrElse);
        }
        public static Expression<Func<T, bool>> Compose<T>(this Expression<Func<T, bool>> exp1, Expression<Func<T, bool>> exp2, Func<Expression, Expression, Expression> merge)
        {
            var parameter = Expression.Parameter(typeof(string), "name");
            SetParamExpressionVisitor visitor = new SetParamExpressionVisitor(parameter);
            var newExp1 = visitor.Modify(exp1.Body);
            var newExp2 = visitor.Modify(exp2.Body);
            var newBodyExp = merge(newExp1, newExp2);
            return Expression.Lambda<Func<T, bool>>(newBodyExp, parameter);
        }
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> exp)
        {
            return Expression.Lambda<Func<T, bool>>(Expression.Not(exp.Body), exp.Parameters[0]);
        }
        #endregion

        #region Expression<Predicate<T>>擴展
        public static Expression<Predicate<T>> And<T>(this Expression<Predicate<T>> exp1, Expression<Predicate<T>> exp2)
        {
            return exp1.Compose(exp2, Expression.AndAlso);
        }
        public static Expression<Predicate<T>> Or<T>(this Expression<Predicate<T>> exp1, Expression<Predicate<T>> exp2)
        {
            return exp1.Compose(exp2, Expression.OrElse);
        }
        public static Expression<Predicate<T>> Compose<T>(this Expression<Predicate<T>> exp1, Expression<Predicate<T>> exp2, Func<Expression, Expression, Expression> merge)
        {
            var parameter = Expression.Parameter(typeof(T), "name");
            SetParamExpressionVisitor visitor = new SetParamExpressionVisitor(parameter);
            var newExp1 = visitor.Modify(exp1.Body);
            var newExp2 = visitor.Modify(exp2.Body);
            var newBodyExp = merge(newExp1, newExp2);
            return Expression.Lambda<Predicate<T>>(newBodyExp, parameter);
        }
        public static Expression<Predicate<T>> Not<T>(this Expression<Predicate<T>> exp)
        {
            return Expression.Lambda<Predicate<T>>(Expression.Not(exp.Body), exp.Parameters[0]);
        }
        #endregion

    }
View Code

 

調用:

Expression<Func<string, bool>> exp1 = item => item.Length < 2;
Expression<Func<string, bool>> exp2 = item => item.Length > 4;
//Func<string, bool> func = exp1.And(exp2).Compile();
Func<string, bool> func = exp1.Or(exp2).Not().Compile();
bool b = func("aaa");

 

 

 

參考:

https://www.cnblogs.com/FlyEdward/archive/2010/12/06/Linq_ExpressionTree7.html

https://www.cnblogs.com/snailblog/p/11525118.html(多個Parameter)

未完待續...


免責聲明!

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



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