博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 使用Emit实现动态AOP框架 (三)
阅读量:4306 次
发布时间:2019-06-06

本文共 14586 字,大约阅读时间需要 48 分钟。

     目  录

准备工作完成后,DynamicProxy类就可以开始了。

创建代理对象 Create

    创建代理对象主要分为五步:

   (1)、获取被代理类型构造函数参数列表

Type[] parameterTypes = parameters == null ? Type.EmptyTypes : parameters.Select(p => p.GetType()).ToArray();  (2)、根据构造函数参数列表创建代理类型
Type proxyType = CreateProxyType(srcType, parameterTypes);  (3)、使用动态方法生成创建代理类型实例的委托
CreateFunc
(proxyType, parameterTypes) (4)、生成ProxyType对象,存入代理类型字典,以备二次调用
obj = new ProxyType
(srcType.FullName, signature, CreateFunc
(proxyType, parameterTypes)); func_Dictionary.Add(srcType.FullName + "(" + signature + ")", obj); (5)、通过委托生成代理对象
Func
func = (obj as ProxyType
).CreateFunc; if (func == null) throw new Exception("unknown exception"); return func(parameters);
1         ///  2         /// 创建代理类型 3         ///  4         /// 类型 5         /// 参数 6         /// 
7 private static Type CreateProxyType(Type srcType, Type[] parameterTypes) 8 { 9 XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection10 (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         ///  2          /// 创建代理类型 3         ///  4         /// 类型 5         /// 参数 6         /// 
7 private static Type CreateProxyType(Type srcType, Type[] parameterTypes) 8 { 9 XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection10 (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        ///  2         /// 重写被代理类的属性 3         ///  4         ///  5         /// 属性信息 6         /// 切面范围 7         /// 切面公共调用方法 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             //覆盖自动生成的Getter28             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             //覆盖自动生成的Setter45             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         ///  2         /// 重写被代理类的指定方法 3         ///  4         /// 类型 5         /// 被代理方法 6         /// 代理特性集合 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         ///  2         ///  3         ///  4         ///  5         ///  6         ///  7         ///  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                 //调用BeforeInvoke35                 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   ///  2         /// 生成切面上下文对象 3         ///  4         ///  5         ///  方法名称 6         /// 参数类型 7         /// 
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         ///  2         /// 生成创建代理类型实例的委托 3         ///  4         /// 
被代理类型
5 /// 代理类型 6 /// 代理类型构造函数参数类型 7 ///
8 private static Func
CreateFunc
(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 else26 // 如果是引用类型,转换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
)) as Func
;39 }
View Code

1.3 ProxyType类

1   public class ProxyType
2 { 3 #region 构造函数 4 ///
5 /// 构造函数 6 /// 7 ///
类型名称 8 ///
构造函数参数签名 9 ///
创建被代理类型实例的委托10 public ProxyType(string name, string parameterSignature, Func
createFunc)11 {12 Name = name; ParameterSignature = parameterSignature; CreateFunc = createFunc;13 }14 #endregion15 16 #region 属性17 18 ///
19 /// 名称20 /// 21 public string Name { get; set; }22 23 ///
24 /// 参数类型签名25 /// 26 public string ParameterSignature { get; set; }27 28 ///
29 /// 创建被代理类型实例的委托30 /// 31 public Func
CreateFunc { get; set; }32 33 #endregion34 }
View Code

  到此为止一个简单的Aop框架就完成了。下一篇会介绍一个下BuilderCollection类

 

转载于:https://www.cnblogs.com/accode/p/10903042.html

你可能感兴趣的文章