• 表达式:使用API创建表达式树(4)DynamicExpression


    DynamicExpression:表示动态操作。这个网上可见的资料少得可怜,但想到MVC和第三方的动态语言能在NET运行。好奇的倒腾了下

    先声明两个类(有相同的方法和字段,但不是继承于同一接口的类),设想是动态调用它们的方法和字段。

        class AiTestD
            {
                public string Name = "你好!这是 AiTestD";
                public int Id = 123;
                public static string AiTest(string ai1, string ai2)
                {
                    return ai1 + ai2;
                }
    
                public static int add(int a, int b)
                {
    
                    return a + b;
                }
    
                public int add2(int a, int b)
                {
    
                    return -(a + b);
                }
            }
    
            class AiTestD2
            {
                public string Name = "你好!这是 AiTestD2";
                public int Id = 789;
                public static string AiTest(string ai1, string ai2)
                {
                    return "**" + ai1 + ai2;
                }
                public static int add(int a, int b)
                {
                    return (a + b) * 1000;
                }
                public int add2(int a, int b)
                {
                    return -(a + b) * 1000;
                }
            }

    第一个方法 AiDynamicDo,要实现的是获取两个类的Id属性质(这里是值类型操作,刚开始时,定义的是typeof(Func<CallSite, object, int>,总是编译不过,发现在 Expression.MakeDynamic 中的参数,只要是值类型都是通不过的,只有通过Expression.Convert转换成 typeof(object),才可以,但引用类型是不用转换的)

     

            /// <summary>
            /// 获取字段
            /// </summary>
            /// <param name="aiD"></param>
            static void AiDynamicDo(dynamic aiD)
            {
                //声明参数
                ParameterExpression paramExpr = Expression.Parameter(typeof(object), "o");
                //获取 CallSite 以支持调用时的运行时。
                //CallSiteBinder 是必需的
            //注意这里用的是     Binder.GetMember    
            CallSiteBinder aiBinder = Binder.GetMember(CSharpBinderFlags.None, "Id", typeof(Program),
                    new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
                //定义一个动态表达式
                //Func<CallSite, object, object>声明方式中 CallSite 是动态调用站点的基类。 此类型用作动态站点目标的参数类型。
                //就是上面的 aiBinder,第二个参数是要传入的动态类型 用dynamic关键字也是可以的,
                //后面的参数是实际调用和返回的参数
                //不过操作中发现在返回值一定要用 object 不然会编译不过
                //当然也可用Action<CallSite, object,...>,除了没返回值,参数要求和用Func<CallSite, object, object>是一样的。
               
                DynamicExpression Dynamic2 =
                  Expression.MakeDynamic(typeof(Func<CallSite, object, object>),
                     aiBinder, paramExpr
              );
                //编译
                LambdaExpression laExp = Expression.Lambda(
                    Expression.Block(
                    new ParameterExpression[] { paramExpr },
                    Expression.Assign(paramExpr, Expression.Constant(aiD))
                  , Dynamic2));
                //执行
                Console.WriteLine("AiDynamicDo:" + laExp.ToString());
                Console.WriteLine("结果:" + laExp.Compile().DynamicInvoke());
                Console.WriteLine();
    
            }

    调用:    

          AiDynamicDo(new AiTestD());

          AiDynamicDo(new AiTestD2());


    输出为:
          AiDynamicDo:() => {var o; ... }
            结果:123

            AiDynamicDo:() => {var o; ... }
            结果:789

        /// <summary>
            /// 字段2
            /// </summary>
            /// <param name="aiD"></param>
            static void AiDynamicDo2(dynamic aiD)
            {
                //Binder.Convert
                CallSiteBinder aiBinder = Binder.Convert(CSharpBinderFlags.None, typeof(object), typeof(Program));
                ParameterExpression paramExpr = Expression.Parameter(aiD.GetType(), "o");
                MemberExpression namePropExpr = Expression.Field(paramExpr, "Name");
                var Dynamic2 = Expression.MakeDynamic(typeof(Func<CallSite, object, object>)
                    , aiBinder
                    , namePropExpr
              );
                LambdaExpression laExp = Expression.Lambda(
                  Expression.Block(
                  new ParameterExpression[] { paramExpr },
                  Expression.Block(Expression.Assign(paramExpr, Expression.Constant(aiD))
                  )
                 , Dynamic2));
                Console.WriteLine("AiDynamicDo2:" + laExp.ToString());
                Console.WriteLine("结果:" + laExp.Compile().DynamicInvoke());
                Console.WriteLine();
            }
    
            /// <summary>
            /// 引用类型方法调用测试 Binder.Convert
            /// </summary>
            /// <param name="aiD"></param>
            static void AiDynamicDo3(dynamic aiD)
            {
                //Binder.Convert
                CallSiteBinder aiBinder = Binder.Convert(CSharpBinderFlags.None, typeof(object), typeof(Program));
                ParameterExpression aiParamExpr = Expression.Parameter(aiD.GetType(), "o");
                ParameterExpression aiParamExpr1 = Expression.Parameter(typeof(string), "a");
                ParameterExpression aiParamExpr2 = Expression.Parameter(typeof(string), "b");
                MethodCallExpression aiMth = Expression.Call(
                    null, aiD.GetType().GetMethod("AiTest", new Type[] { typeof(string), typeof(string) }), aiParamExpr1, aiParamExpr2);
                var Dynamic2 =
                  Expression.MakeDynamic(
                  typeof(Func<CallSite, dynamic, object>),
                  aiBinder, aiMth
    
              );
                LambdaExpression laExp = Expression.Lambda(Dynamic2, aiParamExpr1, aiParamExpr2);
                Console.WriteLine("AiDynamicDo3:" + laExp.ToString());
                Console.WriteLine("结果:" + laExp.Compile().DynamicInvoke("AiTest-", "动态调用"));
                Console.WriteLine();
            }
    
            /// <summary>
            /// 值类型方法调用测试 Binder.Convert
            /// </summary>
            /// <param name="aiD"></param>
            static void AiDynamicDo4(dynamic aiD)
            {
                CallSiteBinder aiBinder = Binder.Convert(CSharpBinderFlags.None, typeof(object), typeof(Program));
                ParameterExpression aiParamExpr = Expression.Parameter(aiD.GetType(), "o");
                ParameterExpression aiParamExpr1 = Expression.Parameter(typeof(int), "a");
                ParameterExpression aiParamExpr2 = Expression.Parameter(typeof(int), "b");
    
                MethodCallExpression aiMth = Expression.Call(
                    null, aiD.GetType().GetMethod("add", new Type[] { typeof(int), typeof(int) }), aiParamExpr1, aiParamExpr2);
                var Dynamic2 =
                  Expression.MakeDynamic(
                  typeof(Func<CallSite, dynamic, object>),
                 aiBinder,
                  Expression.Convert(aiMth, typeof(object)) //!!这里要转换,否刚不能通过
    
              );
                //LambdaExpression laExp = Expression.Lambda(Dynamic2, paramExpr1, paramExpr2);
                LambdaExpression laExp = Expression.Lambda(
                     Expression.Block(
                    new ParameterExpression[] { aiParamExpr1, aiParamExpr2 },
                    Expression.Block(Expression.Assign(aiParamExpr1, Expression.Constant(30)),
                    Expression.Assign(aiParamExpr2, Expression.Constant(40))
                    ),
                    Dynamic2
                    )
                );
                Console.WriteLine("AiDynamicDo4:" + laExp.ToString());
                Console.WriteLine("结果:" + laExp.Compile().DynamicInvoke());
                Console.WriteLine();
            }

        //与上例不同的是,本过程不是调用的反射方法
    static void AiDynamicDo5(dynamic aiD) { //当调用方法是void类型时 应该用 CSharpBinderFlags.ResultDiscarded //第二个参数是方法名 //第三个参数要泛型时才结出 //第五个参数要与表达示参数据相同 var aiBinder = Binder.InvokeMember(CSharpBinderFlags.None, "add2", null, typeof(Program), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); ParameterExpression aiParamExpr = Expression.Parameter(typeof(object), "o"); ParameterExpression aiParamExpr1 = Expression.Parameter(typeof(int), "a"); ParameterExpression aiParamExpr2 = Expression.Parameter(typeof(int), "b");         //与上例中不同的地方 DynamicExpression aiDynamic = Expression.MakeDynamic(typeof(Func<CallSite, object, int, int, object>) , aiBinder , aiParamExpr , aiParamExpr1 , aiParamExpr2 ); //下面这种使用方式,在调用时DynamicInvoke(aiD,30,40) //LambdaExpression laExp = Expression.Lambda(Dynamic2, paramExpr, paramExpr1, paramExpr2); LambdaExpression aiLabExp = Expression.Lambda( Expression.Block( new ParameterExpression[] { aiParamExpr, aiParamExpr1, aiParamExpr2 } , Expression.Assign(aiParamExpr, Expression.Constant(aiD)) , Expression.Assign(aiParamExpr1, Expression.Constant(30)) , Expression.Assign(aiParamExpr2, Expression.Constant(40)) , aiDynamic)); Console.WriteLine("AiDynamicDo5:" + aiLabExp.ToString()); Console.WriteLine("结果:" + aiLabExp.Compile().DynamicInvoke()); Console.WriteLine(); }

    调用:
                AiDynamicDo2(new AiTestD());

                AiDynamicDo2(new AiTestD2());

                AiDynamicDo3(new AiTestD());

                AiDynamicDo3(new AiTestD2());

                AiDynamicDo4(new AiTestD());

                AiDynamicDo4(new AiTestD2());

                AiDynamicDo5(new AiTestD());

                AiDynamicDo5(new AiTestD2());

    输出:
        AiDynamicDo2:() => {var o; ... }
        结果:你好!这是 AiTestD

        AiDynamicDo2:() => {var o; ... }
        结果:你好!这是 AiTestD2

        AiDynamicDo3:(a, b) => Convert System.Object(AiTest(a, b))
        结果:AiTest-动态调用

        AiDynamicDo3:(a, b) => Convert System.Object(AiTest(a, b))
        结果:**AiTest-动态调用

        AiDynamicDo4:() => {var a;var b; ... }
        结果:70

        AiDynamicDo4:() => {var a;var b; ... }
        结果:70000

        AiDynamicDo5:() => {var o;var a;var b; ... }
        结果:-70

        AiDynamicDo5:() => {var o;var a;var b; ... }
        结果:-70000

  • 相关阅读:
    selenium-使用xpath结合text内容定位元素
    pip 安装第三方库报错解决方法
    本地使用git拉取远程指定分支代码
    Python之字符串格式化(format)
    Python之字符串format格式化
    Python中的eval()函数
    用PIL实现滤镜(一)——素描、铅笔画效果
    python勾画图片轮廓
    用python读取带密码的excel文件中的数据
    python中的列表与列表推导式
  • 原文地址:https://www.cnblogs.com/athinker/p/3596187.html
Copyright © 2020-2023  润新知