.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
未完待续