DynamicMethodFactory的作用就像它的名字一样,构建动态的方法。
所产生的动态方法基于两种委托类型:分别对应实例方法和静态方法,下面重点说静态的动态方法。
1 public delegate object StaticDynamicMethodProxyHandler(object[] paramObjs); 2 public delegate object DynamicMethodProxyHandler(object ownerInstance, object[] paramObjs);
基于委托StaticDynamicMethodProxyHandler, 动态创建一个方法,用StaticDynamicMethodProxyHandler传进来的参数作为genericMethodInfo方法的参数进行调用。
传参数的工作由LoadParameters()方法完成,因为委托中参数是用objcet数组的形式传进来的,所以现在就要将object数组的对象按照genericMethodInfo方法中的参数列表进行类型转换,
然后加载到堆栈内。
1 protected static StaticDynamicMethodProxyHandler DoGetStaticMethodDelegate( 2 Module targetModule, 3 MethodInfo genericMethodInfo, 4 params Type[] genericParameterTypes) 5 { 6 7 //Create a dynamic method proxy delegate used to call the specified methodinfo 8 CodeGenerator gen = new CodeGenerator(targetModule); 9 gen.BeginMethod("dm" + Guid.NewGuid().ToString("N"), typeof(StaticDynamicMethodProxyHandler)); 10 11 MethodInfo makeGenericMethodInfo = MakeMethodGeneric(genericMethodInfo, genericParameterTypes); 12 LoadParameters(gen, makeGenericMethodInfo.GetParameters(), true);//将StaticDynamicMethodProxyHandler委托传入的参数,转给genericMethodInfo方法调用 13 gen.Call(makeGenericMethodInfo); 14 15 CastValueToObject(gen, makeGenericMethodInfo.ReturnType); 16 17 return (StaticDynamicMethodProxyHandler)gen.EndMethod(); 18 }
LoadParameters方法:out参数类型与ref参数类型的差别如下,
C#: void ILStudy(out int abc,ref int acc,ref string[] aaa,out string[] ccc)
IL: void ILStudy([out] int32& abc,int32& acc,string[]& aaa,[out] string[]& ccc)
在这里注意区分 ParameterInfo[] pis 参数和gen.Ldarg(0)参数的差别:gen.Ldarg(0)是新定义的方法的参数,也就是所基于的委托的参数列表。
而pis是当前动态方法里面所要调用的方法genericMethodInfo的参数列表。
1 private static void LoadParameters(CodeGenerator gen, ParameterInfo[] pis, bool isMethodStatic) 2 { 3 Check.Require(gen, "gen"); 4 5 //gen.Ldarg所加载的是从委托那边定义的参数,即 object DynamicMethodProxyHandler(object ownerInstance, object[] paramObjs); 6 //而ParameterInfo[] pis参数的作用,就是将委托中paramObjs,转化为pis所对应的参数类型,然后调用参数列表所对应的方法 7 if (pis != null) 8 { 9 for (int i = 0; i < pis.Length; ++i) 10 { //加载委托中参数 object[] paramObjs 11 if (isMethodStatic) 12 { 13 gen.Ldarg(0);//Ldarg是针对产生gen的方法的上下文决定的,方法上下文有参数列表 14 } 15 else 16 { //实例方法 arg0 是this对象,所以第一个参数是arg1 17 gen.Ldarg(1); 18 } 19 //将索引值 index 推送到堆栈上。 20 gen.Ldc(i); 21 22 Type srcType = pis[i].ParameterType; 23 string str = srcType.ToString(); 24 25 //对比方法 26 //IL: void ILStudy([out] int32& abc,int32& acc,string[]& aaa,[out] string[]& ccc) 27 //C#: void ILStudy(out int abc,ref int acc,ref string[] aaa,out string[] ccc) 28 if (str.EndsWith("&")) 29 { 30 srcType = CommonUtils.GetType(str.Substring(0, str.Length - 1)); 31 } 32 33 if (str.EndsWith("&")) //ref or out param 34 { 35 if (srcType.IsValueType && (pis[i].Attributes & ParameterAttributes.Out) != ParameterAttributes.Out) //ref value param 36 { 37 //根据object类型的指令:将数组第i个数据,取为object形式 38 gen.Ldelem(typeof(object)); 39 gen.Unbox(srcType); 40 } 41 else 42 { 43 if (srcType.IsValueType && srcType != typeof(object)) //out value param 44 { 45 //先保存,srcType的初始类型 46 gen.LoadDefaultValue(srcType); 47 gen.Box(srcType); 48 gen.Stelem(typeof(object)); 49 50 if (isMethodStatic) 51 { 52 gen.Ldarg(0); 53 } 54 else 55 { 56 gen.Ldarg(1); 57 } 58 gen.Ldc(i); 59 gen.Ldelem(typeof(object)); 60 gen.Unbox(srcType); 61 } 62 else //ref or out class param 63 { 64 gen.Ldelema(typeof(object)); 65 } 66 } 67 } 68 else 69 { 70 gen.Ldelem(typeof(object)); 71 //转为实际类型 72 if (srcType.IsValueType) 73 { 74 gen.UnboxAny(srcType); 75 } 76 else if (srcType != typeof(object)) 77 { 78 gen.Castclass(srcType); 79 } 80 } 81 } 82 } 83 }