zoukankan      html  css  js  c++  java
  • 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)

    未完待续...

  • 相关阅读:
    计算机视觉资源合集
    EMZ-搭建DL模型的最简便的方式 | 附项目地址
    在边缘设备上拟合大型神经网络的方法总结
    归一化方法总结 | 又名“BN和它的后浪们“
    名词解释 | 论文中的Ablation study
    知识蒸馏的简要概述
    如何看待计算机视觉未来的走向(二)从产品的角度聊一聊
    STL源码分析--functional
    STL源码分析--algorithm
    STL源码分析--bitset
  • 原文地址:https://www.cnblogs.com/fanfan-90/p/12128845.html
Copyright © 2011-2022 走看看