• .NET 动态调用那些事


    传统方法和委托调用

            /// <summary>
            /// the English speaker.
            /// </summary>
            /// <param name="name">The name.</param>
            public void EnglishSpeaker(string name)
            {
                Console.WriteLine(
                    string.Format("Hello my name is {0} and I am English speaker.\n", name));
            }
    
            /// <summary>
            /// the Chineses speaker.
            /// </summary>
            public void ChineseSpeaker(string name)
            {
                Console.WriteLine(
                    string.Format("您好我的名字叫{0},我是讲普通话的。\n", name));
            }
    

    (1)不使用委托调用的方式:

            /// <summary>
            /// 根据上下文调用不同的方法
            /// </summary>
            /// <param name="name">string</param>
            /// <param name="lang">enum</param>
            private static void Say(string name, Language lang)
            {
                switch (lang)
                {
                    case Language.Chinese:
                        Program.ChineseSpeaker(name);
                        break;
                    case Language.English:
                        Program.EnglishSpeaker(name);
                        break;
                    default :
                        break;
                }
            }
    

    (2)使用委托调用:

            /// <summary>
            /// Define speak delegate.
            /// </summary>
            /// <param name="name"></param>
            private delegate void SpeakDelegate(string name);
    
            /// <summary>
            /// The base say function.
            /// </summary>
            /// <param name="name">The name.</param>
            /// <param name="speaker">The speaker.</param>
            private static void Say(string name, SpeakDelegate speaker)
            {
                ///Inoke the speaker function.
                speaker(name);
            }
    
            ///传递函数名进行委托方法绑定
            Program.Say("钧航", ChineseSpeaker);
            Program.Say("JK.Rush", EnglishSpeaker);
    

    动态调用方法:

    (1)反射发出调用

    使用 DynamicMethod 类在运行时定义轻量全局方法,然后使用委托执行这些方法。

    public class MyMath
    {
        public double Add1(int a, float b)
        {
            return a + b;
        }
            
        public double Add2(int a,float b)
        {
            return a+b+3;
        }
    }
    var addMethod = typeof(MyMath).GetMethod("Add1");
    var dynamicMethod = new DynamicMethod("", typeof(double), new[] { typeof(MyMath), typeof(int), typeof(float) });
    //
    var il = dynamicMethod.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Ldarg_2);
    il.Emit(OpCodes.Callvirt, addMethod);
    il.Emit(OpCodes.Ret);
    //
    var add = (Func<MyMath, int, float, double>)dynamicMethod.CreateDelegate(typeof(Func<MyMath, int, float, double>));
    //
    var math = new MyMath();
    var result = add(math, 1, 2.0);

    从第 5 行起,使用几个 IL 汇编指令,简单一说:

    • 第 5 行,OpCodes.Ldarg_0 是将索引为 0 的参数值推送到堆栈上,Ldarg_1、Ldarg_2 以此类推;
    • 第 6 行,OpCodes.Callvirt 是调用对象的(后期绑定)方法,并且将返回值推送到计算堆栈上;
    • 第 9 行,OpCodes.Ret 表达从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。

    反射发出是在汇编级别的,很底层,也就意味着效率更高、威力更强大。反射发出能绕过跳过 JIT 可见性检查,访问 private 成员。

    (2)反射动态调用方法(略)http://www.cnblogs.com/focusonnet/archive/2009/04/17/1438013.html

     未完待续

  • 相关阅读:
    C/C++一些库函数的实现
    约瑟夫环问题(Josephus)
    union关键字及大小端模式
    指针数组和数组指针
    巧用位运算
    C/C++生成可执行文件过程
    C语言+Modbus+NXP整体规划
    bug和待完善
    python学习第二课
    python学习第一课
  • 原文地址:https://www.cnblogs.com/zhanghaomars/p/3006411.html
Copyright © 2020-2023  润新知