準備工作完成後,DynamicProxy類就可以開始了。 創建代理對象 Create 創建代理對象主要分為五步: (1)、獲取被代理類型構造函數參數列表 1 /// <summary> 2 /// 創建代理類型 3 /// </summary> 4 /// <param name="srcType" ...
準備工作完成後,DynamicProxy類就可以開始了。
創建代理對象 Create
創建代理對象主要分為五步:
(1)、獲取被代理類型構造函數參數列表
Type[] parameterTypes = parameters == null ? Type.EmptyTypes : parameters.Select(p => p.GetType()).ToArray();
(2)、根據構造函數參數列表創建代理類型
Type proxyType = CreateProxyType(srcType, parameterTypes);
(3)、使用動態方法生成創建代理類型實例的委托
CreateFunc<T>(proxyType, parameterTypes)
(4)、生成ProxyType對象,存入代理類型字典,以備二次調用
obj = new ProxyType<T>(srcType.FullName, signature, CreateFunc<T>(proxyType, parameterTypes)); func_Dictionary.Add(srcType.FullName + "(" + signature + ")", obj);
(5)、通過委托生成代理對象
Func<object[], T> func = (obj as ProxyType<T>).CreateFunc;
if (func == null)
throw new Exception("unknown exception");
return func(parameters);
1 /// <summary> 2 /// 創建代理類型 3 /// </summary> 4 /// <param name="srcType">類型</param> 5 /// <param name="parameterTypes">參數</param> 6 /// <returns></returns> 7 private static Type CreateProxyType(Type srcType, Type[] parameterTypes) 8 { 9 XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection 10 (srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); 11 12 13 foreach (var propertyInfo in srcType.GetProperties()) 14 OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); 15 16 //切入方法 17 MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); 18 19 for (int i = 0; i < methods.Length; i++) 20 { 21 var method = methods[i]; 22 23 if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; 24 25 object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); 26 27 OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes); 28 } 29 30 Type result = bc.DynamicTypeBuilder.CreateType(); 31 32 bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); 33 34 return result; 35 }View Code
1.1、根據構造函數參數列表創建代理類型 CreateProxyType
(1)、通過Emit生成動態程式集、動態模塊以及動態類型
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes);
(2)、重寫被切入的屬性
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo);
(3)、重寫被切入的方法
OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
(4)、生成代理類型
Type result = bc.DynamicTypeBuilder.CreateType();
1 /// <summary> 2 /// 創建代理類型 3 /// </summary> 4 /// <param name="srcType">類型</param> 5 /// <param name="parameterTypes">參數</param> 6 /// <returns></returns> 7 private static Type CreateProxyType(Type srcType, Type[] parameterTypes) 8 { 9 XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection 10 (srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); 11 12 13 foreach (var propertyInfo in srcType.GetProperties()) 14 OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); 15 16 //切入方法 17 MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); 18 19 for (int i = 0; i < methods.Length; i++) 20 { 21 var method = methods[i]; 22 23 if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; 24 25 object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); 26 27 OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes); 28 } 29 30 Type result = bc.DynamicTypeBuilder.CreateType(); 31 32 bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); 33 34 return result; 35 }View Code
1.1.1 重寫被切入的屬性 OverrideProperty
1 /// <summary> 2 /// 重寫被代理類的屬性 3 /// </summary> 4 /// <param name="dynamicTypeBuilder"></param> 5 /// <param name="info">屬性信息</param> 6 /// <param name="rangeType">切麵範圍</param> 7 /// <param name="onEntryExit">切麵公共調用方法</param> 8 private static void OverrideProperty(TypeBuilder dynamicTypeBuilder, PropertyInfo info) 9 { 10 //不需要切入直接返回 11 object[] aspectAttributes = info.GetCustomAttributes(typeof(AspectAttribute), false); 12 13 if (aspectAttributes.Length == 0) return; 14 15 PropertyBuilder dynamicPropertyBuilder = dynamicTypeBuilder.DefineProperty(info.Name, PropertyAttributes.HasDefault, info.PropertyType, null); 16 17 //Getter Setter 方法標識 18 MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; 19 20 MethodBuilder getter = dynamicTypeBuilder.DefineMethod("get_" + info.Name, getSetAttr, info.PropertyType, Type.EmptyTypes); 21 22 ILGenerator getIL = getter.GetILGenerator(); 23 24 ILGenerateProxyMethod(getIL, info.GetGetMethod(), Type.EmptyTypes, aspectAttributes); 25 26 27 //覆蓋自動生成的Getter 28 MethodInfo getMethod = info.GetGetMethod(); 29 30 if (getMethod != null) dynamicTypeBuilder.DefineMethodOverride(getter, getMethod); 31 32 //給屬性設置Get、Set方法 33 dynamicPropertyBuilder.SetGetMethod(getter); 34 35 36 //重寫Set 方法 37 MethodBuilder setter = dynamicTypeBuilder.DefineMethod("set_" + info.Name, getSetAttr, typeof(void), new Type[] { info.PropertyType }); 38 39 ILGenerator setIL = setter.GetILGenerator(); 40 41 ILGenerateProxyMethod(setIL, info.GetSetMethod(), new Type[] { info.PropertyType }, aspectAttributes); 42 43 44 //覆蓋自動生成的Setter 45 MethodInfo setMethod = info.GetSetMethod(); 46 47 if (setMethod != null) dynamicTypeBuilder.DefineMethodOverride(setter, setMethod); 48 49 dynamicPropertyBuilder.SetSetMethod(setter); 50 }View Code
1.1.2 重寫被切入的方法 OverrideMethod
1 /// <summary> 2 /// 重寫被代理類的指定方法 3 /// </summary> 4 /// <param name="typeBuilder">類型</param> 5 /// <param name="src_Method">被代理方法</param> 6 /// <param name="aspectAttributes">代理特性集合</param> 7 private static void OverrideMethod(TypeBuilder typeBuilder, MethodInfo src_Method, object[] aspectAttributes) 8 { 9 if (aspectAttributes == null || aspectAttributes.Length == 0) return; 10 11 MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; 12 13 //獲取當前方法參數列表 14 Type[] paramTypes = XDynamic.GetMethodParameterTypes(src_Method); 15 16 ILGenerator il = typeBuilder.DefineMethod(src_Method.Name, attr, src_Method.ReturnType, paramTypes).GetILGenerator(); 17 18 ILGenerateProxyMethod(il, src_Method, paramTypes, aspectAttributes); 19 }View Code
1.1.3 生成代理方法 ILGenerateProxyMethod
1 /// <summary> 2 /// 3 /// </summary> 4 /// <param name="il_ProxyMethod"></param> 5 /// <param name="src_Method"></param> 6 /// <param name="paramTypes"></param> 7 /// <param name="aspectAttributes"></param> 8 private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes) 9 { 10 int aspectCount = aspectAttributes.Length; 11 12 //生成切麵上下文 13 LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes); 14 15 //申明臨時存放切麵對象和OnExit方法的變數 16 var aspectLocalBuilders = new LocalBuilder[aspectCount]; 17 var onExit_Methods = new MethodInfo[aspectCount]; 18 19 20 //初始化標記的切麵對象,並調用切麵對象的OnEntry方法 21 for (int i = 0; i < aspectCount; i++) 22 { 23 //創建一個切麵對象 24 var aspectType = aspectAttributes[i].GetType(); 25 var aspect = il_ProxyMethod.DeclareLocal(aspectType); 26 ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes); 27 28 il_ProxyMethod.Emit(OpCodes.Newobj, constructor); 29 il_ProxyMethod.Emit(OpCodes.Stloc, aspect); 30 31 var onEntry_method = aspectType.GetMethod("OnEntry"); 32 onExit_Methods[i] = aspectType.GetMethod("OnExit"); 33 34 //調用BeforeInvoke 35 il_ProxyMethod.Emit(OpCodes.Ldloc, aspect); 36 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); 37 il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method); 38 il_ProxyMethod.Emit(OpCodes.Nop); 39 40 aspectLocalBuilders[i] = aspect; 41 } 42 43 //類對象,參數值依次入棧 44 for (int i = 0; i <= paramTypes.Length; i++) 45 il_ProxyMethod.Emit(OpCodes.Ldarg, i); 46 47 //調用基類的方法 48 il_ProxyMethod.Emit(OpCodes.Call, src_Method); 49 50 51 //定義返回值 52 LocalBuilder result = null; 53 54 //如果有返回值,保存返回值到局部變數 55 if (src_Method.ReturnType != typeof(void)) 56 { 57 result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType); 58 il_ProxyMethod.Emit(OpCodes.Stloc, result); 59 60 //給AspectContext的屬性Result賦值 61 var resultSetMethod = typeof(AspectContext).GetMethod("set_Result"); 62 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //載入AspectContext局部變數 63 il_ProxyMethod.Emit(OpCodes.Ldloc, result);//載入返回值 64 il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType); 65 il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//賦值 66 } 67 68 //調用橫切對象的OnExit方法 69 for (int i = 0; i < aspectCount; i++) 70 { 71 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]); 72 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); 73 il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]); 74 il_ProxyMethod.Emit(OpCodes.Nop); 75 } 76 77 //如果有返回值,則把返回值壓棧 78 if (result != null) 79 il_ProxyMethod.Emit(OpCodes.Ldloc, result); 80 81 il_ProxyMethod.Emit(OpCodes.Ret);//返回 82 }View Code
1.1.4 生成切麵上下文對象 CreateAspectContext
1 /// <summary> 2 /// 生成切麵上下文對象 3 /// </summary> 4 /// <param name="il"></param> 5 /// <param name="methodName">方法名稱</param> 6 /// <param name="paramTypes">參數類型</param> 7 /// <returns></returns> 8 private static LocalBuilder CreateAspectContext(ILGenerator il, string methodName, Type[] paramTypes) 9 { 10 //AspectContext.ParameterArgs 類型為 object[] 11 12 //聲明一個類型為object的局部數組 13 il.DeclareLocal(typeof(object[])); 14 //數組長度入棧 15 il.Emit(OpCodes.Ldc_I4, paramTypes.Length); 16 //生成新數組 17 il.Emit(OpCodes.Newarr, typeof(object)); 18 //賦值給局部數組變數 19 il.Emit(OpCodes.Stloc_0); 20 21 //遍歷參數,並存入數組 22 for (int i = 0; i < paramTypes.Length; i++) 23 { 24 il.Emit(OpCodes.Ldloc_0);//數組入棧 25 il.Emit(OpCodes.Ldc_I4, i);//數組下標入棧 26 il.Emit(OpCodes.Ldarg, i + 1);//按下標載入對應的參數 27 if (paramTypes[i].IsValueType)//參數為值類型,裝箱 28 il.Emit(OpCodes.Box, paramTypes[i]); 29 il.Emit(OpCodes.Stelem_Ref);//將參數存入數組 30 } 31 32 //獲取AspectContext構造函數 33 Type aspectContextType = typeof(AspectContext); 34 ConstructorInfo info = aspectContextType.GetConstructor(new Type[] { typeof(object), typeof(string), typeof(object[]) }); 35 36 //生成一個AspectContext 對象 37 il.Emit(OpCodes.Ldarg_0);//載入調用對象 38 il.Emit(OpCodes.Ldstr, methodName);//載入方法名稱 39 il.Emit(OpCodes.Ldloc_0);//載入由參數生成的局部數組變數 40 il.Emit(OpCodes.Newobj, info); 41 42 //聲明一個AspectContext局部變數 43 LocalBuilder aspectContext = il.DeclareLocal(aspectContextType); 44 il.Emit(OpCodes.Stloc, aspectContext); 45 46 return aspectContext; 47 }View Code
1.2 使用動態方法生成創建代理類型實例的委托
1 /// <summary> 2 /// 生成創建代理類型實例的委托 3 /// </summary> 4 /// <typeparam name="T">被代理類型</typeparam> 5 /// <param name="proxyType">代理類型</param> 6 /// <param name="parameterTypes">代理類型構造函數參數類型</param> 7 /// <returns></returns> 8 private static Func<object[], T> CreateFunc<T>(Type proxyType, Type[] parameterTypes) 9 { 10 DynamicMethod method = new DynamicMethod(proxyType.Name + "_CF", typeof(T), new Type[] { typeof(object[]) }, true); 11 12 var il = method.GetILGenerator(); 13 14 //根據T類型的構造函數參數列表,依次將 object[] parameters 中對應的值載入到堆棧(並做相應類型轉換),以被T類型的構造函數使用 15 for (int i = 0; i < parameterTypes.Length; i++) 16 { 17 18 il.Emit(OpCodes.Ldarg_0); 19 il.Emit(OpCodes.Ldc_I4, i); 20 il.Emit(OpCodes.Ldelem_Ref); 21 22 if (parameterTypes[i].IsValueType) 23 // 如果是值類型,拆箱 24 il.Emit(OpCodes.Unbox_Any, parameterTypes[i]); 25 else 26 // 如果是引用類型,轉換 27 il.Emit(OpCodes.Castclass, parameterTypes[i]); 28 } 29 30 ConstructorInfo info = proxyType.GetConstructor(parameterTypes); 31 32 if (info == null) throw new Exception("代理類不存在,與指定參數列表相對應的構造函數。"); 33 34 il.Emit(OpCodes.Newobj, info); 35 il.Emit(OpCodes.Ret); 36 37 //建立《生成指定類型T的實例》的委托 38 return method.CreateDelegate(typeof(Func<object[], T>)) as Func<object[], T>; 39 }View Code
1.3 ProxyType類
1 public class ProxyType<T> 2 { 3 #region 構造函數 4 /// <summary> 5 /// 構造函數 6 /// </summary> 7 /// <param name="name">類型名稱</param> 8 /// <param name="parameterSignature">構造函數參數簽名</param> 9 /// <param name="createFunc">創建被代理類型實例的委托</param> 10 public ProxyType(string name, string parameterSignature, Func<object[], T> createFunc) 11 { 12 Name = name; ParameterSignature = parameterSignature; CreateFunc = createFunc; 13 } 14 #endregion 15 16 #region 屬性 17 18 /// <summary> 19 /// 名稱 20 /// </summary> 21 public string Name { get; set; } 22 23 /// <summary> 24 /// 參數類型簽名 25 /// </summary> 26 public string ParameterSignature { get; set; } 27 28 /// <summary> 29 /// 創建被代理類型實例的委托 30 /// </summary> 31 public Func<object[], T> CreateFunc { get; set; } 32 33 #endregion 34 }View Code
到此為止一個簡單的Aop框架就完成了。下一篇會介紹一個下BuilderCollection類