.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

 未完待续

原文地址:https://www.cnblogs.com/zhanghaomars/p/3006411.html