• 表达式树ExpressionTrees


    简介

    表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。
    你可以对表达式树中的代码进行编辑和运算。这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。
    表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性。

    一、Lambda 表达式创建表达式树

                Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
                Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
                Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;
                var lambda = actionExpression.Compile();
                lambda(11);//输出11
                Console.ReadLine();

    二、API 创建表达式树

                //通过 Expression 类创建表达式树
                //  lambda:num => num == 0
                ParameterExpression pExpression = Expression.Parameter(typeof(int));    //参数:num
                ConstantExpression cExpression = Expression.Constant(0);    //常量:0
                BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression);   //表达式:num == 0
                Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression);  //lambda 表达式:num => num == 0
                var aa = lambda.Compile();
                Console.WriteLine("{0}", aa(11));   //false
                Console.WriteLine("{0}", aa(0));    //true
                Console.ReadLine();

    三、解析表达式树 

                Expression<Func<int, bool>> funcExpression = num => num == 0;
    
                //开始解析
                ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表达式参数
                BinaryExpression body = (BinaryExpression)funcExpression.Body;  //lambda 表达式主体:num == 0
    
                Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");
                Console.ReadLine();

    四、表达式树永久性

    表达式树应具有永久性(类似字符串)。这意味着如果你想修改某个表达式树,则必须复制该表达式树然后替换其中的节点来创建一个新的表达式树。  你可以使用表达式树访问者遍历现有表达式树。

    五、编译表达式树

                //Expression<TDelegate> 类型提供了 Compile 方法以将表达式树表示的代码编译成可执行委托。
                Expression<Func<string, int>> funcExpression = msg => msg.Length;
                //表达式树编译成委托
                var lambda = funcExpression.Compile();
                //调用委托
                Console.WriteLine(lambda("Hello, World!")); //13
    
                //语法简化
                Console.WriteLine(funcExpression.Compile()("Hello, World!")); //13
                Console.ReadLine();

    六、执行表达式树

                int n = 1;
                int m = 2;
                var p1 = Expression.Parameter(typeof(int), "num1");
                var p2 = Expression.Parameter(typeof(int), "num2");
                //待执行的表达式树
                BinaryExpression bExpression = Expression.Add(p1, p2);
                //创建 lambda 表达式
                Expression<Func<int,int,int>> funcExpression = Expression.Lambda<Func<int, int, int>>(bExpression, p1, p2);
                //编译 lambda 表达式
                Func<int, int, int> func = funcExpression.Compile();
    
                //执行 lambda 表达式
                Console.WriteLine($"{n} + {m} = {func(n,m)}");
                Console.ReadLine();

    七、修改表达式树

            static void Main(string[] args)
            {
                Expression<Func<int, bool>> funcExpression = num => num == 0;
                Console.WriteLine($"Source: {funcExpression}");//Source: num => (num == 0)
    
                var visitor = new NotEqualExpressionVisitor();
                var expression = visitor.Visit(funcExpression);
    
                Console.WriteLine($"Modify: {expression}");//Source: num => (num != 0)
    
                Console.Read();
            }
    
            /// <summary>
            /// 不等表达式树访问器
            /// </summary>
            public class NotEqualExpressionVisitor : ExpressionVisitor
            {
                public Expression Visit(BinaryExpression node)
                {
                    return VisitBinary(node);
                }
    
                protected override Expression VisitBinary(BinaryExpression node)
                {
                    //该类继承 ExpressionVisitor 类,通过 Visit 方法间接调用 VisitBinary 方法将 != 替换成 ==。基类方法构造类似于传入的表达式树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式树。  
                    return node.NodeType == ExpressionType.Equal
                        ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
                        : base.VisitBinary(node);
                }
            }
  • 相关阅读:
    复杂JSON字符串转换为Java嵌套对象的方法
    好代码是如何炼成的
    让数据流转换代码更加健壮流畅:List的Stream包装
    由一个重构示例引发的对可扩展性的思考
    如何高效搜索信息
    个人安全防护简明指南
    YAML配置解析
    事件处理业务的简易组件编排框架
    lambda表达式滥用之殇:解耦三层嵌套lambda表达式
    碎碎念四六
  • 原文地址:https://www.cnblogs.com/lgxlsm/p/6756174.html
Copyright © 2020-2023  润新知