博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#使用Emit构造拦截器动态代理类
阅读量:7259 次
发布时间:2019-06-29

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

在AOP编程概念介绍中,常见的示例为拦截对象,并在对象的某方法执行前和执行后分别记录日志。

而最常用的拦截方式是使用动态代理类,用其封装一个日志拦截器,当方法被执行时进行日志记录。

日志拦截器类

1 public class Interceptor 2 { 3   public object Invoke(object @object, string @method, object[] parameters) 4   { 5     Console.WriteLine( 6       string.Format("Interceptor does something before invoke [{0}]...", @method)); 7  8     var retObj = @object.GetType().GetMethod(@method).Invoke(@object, parameters); 9 10     Console.WriteLine(11       string.Format("Interceptor does something after invoke [{0}]...", @method));12 13     return retObj;14   }15 }

被拦截对象类

假设我们有一个Command类,包含一个方法Execute用于执行一些工作。

1 public class Command2 {3   public virtual void Execute()4   {5     Console.WriteLine("Command executing...");6     Console.WriteLine("Hello Kitty!");7     Console.WriteLine("Command executed.");8   }9 }

我们需要在Execute方法执行前和执行后分别记录日志。

动态代理类

1 public class Proxy  2 {  3   public static T Of
() where T : class, new() 4 { 5 string nameOfAssembly = typeof(T).Name + "ProxyAssembly"; 6 string nameOfModule = typeof(T).Name + "ProxyModule"; 7 string nameOfType = typeof(T).Name + "Proxy"; 8 9 var assemblyName = new AssemblyName(nameOfAssembly); 10 var assembly = AppDomain.CurrentDomain 11 .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 12 var moduleBuilder = assembly.DefineDynamicModule(nameOfModule); 13 14 var typeBuilder = moduleBuilder.DefineType( 15 nameOfType, TypeAttributes.Public, typeof(T)); 16 17 InjectInterceptor
(typeBuilder); 18 19 var t = typeBuilder.CreateType(); 20 21 return Activator.CreateInstance(t) as T; 22 } 23 24 private static void InjectInterceptor
(TypeBuilder typeBuilder) 25 { 26 // ---- define fields ---- 27 28 var fieldInterceptor = typeBuilder.DefineField( 29 "_interceptor", typeof(Interceptor), FieldAttributes.Private); 30 31 // ---- define costructors ---- 32 33 var constructorBuilder = typeBuilder.DefineConstructor( 34 MethodAttributes.Public, CallingConventions.Standard, null); 35 var ilOfCtor = constructorBuilder.GetILGenerator(); 36 37 ilOfCtor.Emit(OpCodes.Ldarg_0); 38 ilOfCtor.Emit(OpCodes.Newobj, typeof(Interceptor).GetConstructor(new Type[0])); 39 ilOfCtor.Emit(OpCodes.Stfld, fieldInterceptor); 40 ilOfCtor.Emit(OpCodes.Ret); 41 42 // ---- define methods ---- 43 44 var methodsOfType = typeof(T).GetMethods(BindingFlags.Public | BindingFlags.Instance); 45 46 for (var i = 0; i < methodsOfType.Length; i++) 47 { 48 var method = methodsOfType[i]; 49 var methodParameterTypes = 50 method.GetParameters().Select(p => p.ParameterType).ToArray(); 51 52 var methodBuilder = typeBuilder.DefineMethod( 53 method.Name, 54 MethodAttributes.Public | MethodAttributes.Virtual, 55 CallingConventions.Standard, 56 method.ReturnType, 57 methodParameterTypes); 58 59 var ilOfMethod = methodBuilder.GetILGenerator(); 60 ilOfMethod.Emit(OpCodes.Ldarg_0); 61 ilOfMethod.Emit(OpCodes.Ldfld, fieldInterceptor); 62 63 // create instance of T 64 ilOfMethod.Emit(OpCodes.Newobj, typeof(T).GetConstructor(new Type[0])); 65 ilOfMethod.Emit(OpCodes.Ldstr, method.Name); 66 67 // build the method parameters 68 if (methodParameterTypes == null) 69 { 70 ilOfMethod.Emit(OpCodes.Ldnull); 71 } 72 else 73 { 74 var parameters = ilOfMethod.DeclareLocal(typeof(object[])); 75 ilOfMethod.Emit(OpCodes.Ldc_I4, methodParameterTypes.Length); 76 ilOfMethod.Emit(OpCodes.Newarr, typeof(object)); 77 ilOfMethod.Emit(OpCodes.Stloc, parameters); 78 79 for (var j = 0; j < methodParameterTypes.Length; j++) 80 { 81 ilOfMethod.Emit(OpCodes.Ldloc, parameters); 82 ilOfMethod.Emit(OpCodes.Ldc_I4, j); 83 ilOfMethod.Emit(OpCodes.Ldarg, j + 1); 84 ilOfMethod.Emit(OpCodes.Stelem_Ref); 85 } 86 ilOfMethod.Emit(OpCodes.Ldloc, parameters); 87 } 88 89 // call Invoke() method of Interceptor 90 ilOfMethod.Emit(OpCodes.Callvirt, typeof(Interceptor).GetMethod("Invoke")); 91 92 // pop the stack if return void 93 if (method.ReturnType == typeof(void)) 94 { 95 ilOfMethod.Emit(OpCodes.Pop); 96 } 97 98 // complete 99 ilOfMethod.Emit(OpCodes.Ret);100 }101 }102 }

使用动态代理类

1 class Program 2 { 3   static void Main(string[] args) 4   { 5     var command = Proxy.Of(); 6     command.Execute(); 7  8     Console.WriteLine("Hi, Dennis, great, we got the interceptor works."); 9     Console.ReadLine();10   }11 }

运行结果

完整代码

1 using System;  2 using System.Linq;  3 using System.Reflection;  4 using System.Reflection.Emit;  5   6 namespace EmitCreateDynamicProxy  7 {  8   class Program  9   { 10     static void Main(string[] args) 11     { 12       var command = Proxy.Of(); 13       command.Execute(); 14  15       Console.WriteLine("Hi, Dennis, great, we got the interceptor works."); 16       Console.ReadLine(); 17     } 18   } 19  20   public class Command 21   { 22     public virtual void Execute() 23     { 24       Console.WriteLine("Command executing..."); 25       Console.WriteLine("Hello Kitty!"); 26       Console.WriteLine("Command executed."); 27     } 28   } 29  30   public class Interceptor 31   { 32     public object Invoke(object @object, string @method, object[] parameters) 33     { 34       Console.WriteLine( 35         string.Format("Interceptor does something before invoke [{0}]...", @method)); 36  37       var retObj = @object.GetType().GetMethod(@method).Invoke(@object, parameters); 38  39       Console.WriteLine( 40         string.Format("Interceptor does something after invoke [{0}]...", @method)); 41  42       return retObj; 43     } 44   } 45  46   public class Proxy 47   { 48     public static T Of
() where T : class, new() 49 { 50 string nameOfAssembly = typeof(T).Name + "ProxyAssembly"; 51 string nameOfModule = typeof(T).Name + "ProxyModule"; 52 string nameOfType = typeof(T).Name + "Proxy"; 53 54 var assemblyName = new AssemblyName(nameOfAssembly); 55 var assembly = AppDomain.CurrentDomain 56 .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 57 var moduleBuilder = assembly.DefineDynamicModule(nameOfModule); 58 59 var typeBuilder = moduleBuilder.DefineType( 60 nameOfType, TypeAttributes.Public, typeof(T)); 61 62 InjectInterceptor
(typeBuilder); 63 64 var t = typeBuilder.CreateType(); 65 66 return Activator.CreateInstance(t) as T; 67 } 68 69 private static void InjectInterceptor
(TypeBuilder typeBuilder) 70 { 71 // ---- define fields ---- 72 73 var fieldInterceptor = typeBuilder.DefineField( 74 "_interceptor", typeof(Interceptor), FieldAttributes.Private); 75 76 // ---- define costructors ---- 77 78 var constructorBuilder = typeBuilder.DefineConstructor( 79 MethodAttributes.Public, CallingConventions.Standard, null); 80 var ilOfCtor = constructorBuilder.GetILGenerator(); 81 82 ilOfCtor.Emit(OpCodes.Ldarg_0); 83 ilOfCtor.Emit(OpCodes.Newobj, typeof(Interceptor).GetConstructor(new Type[0])); 84 ilOfCtor.Emit(OpCodes.Stfld, fieldInterceptor); 85 ilOfCtor.Emit(OpCodes.Ret); 86 87 // ---- define methods ---- 88 89 var methodsOfType = typeof(T).GetMethods(BindingFlags.Public | BindingFlags.Instance); 90 91 for (var i = 0; i < methodsOfType.Length; i++) 92 { 93 var method = methodsOfType[i]; 94 var methodParameterTypes = 95 method.GetParameters().Select(p => p.ParameterType).ToArray(); 96 97 var methodBuilder = typeBuilder.DefineMethod( 98 method.Name, 99 MethodAttributes.Public | MethodAttributes.Virtual,100 CallingConventions.Standard,101 method.ReturnType,102 methodParameterTypes);103 104 var ilOfMethod = methodBuilder.GetILGenerator();105 ilOfMethod.Emit(OpCodes.Ldarg_0);106 ilOfMethod.Emit(OpCodes.Ldfld, fieldInterceptor);107 108 // create instance of T109 ilOfMethod.Emit(OpCodes.Newobj, typeof(T).GetConstructor(new Type[0]));110 ilOfMethod.Emit(OpCodes.Ldstr, method.Name);111 112 // build the method parameters113 if (methodParameterTypes == null)114 {115 ilOfMethod.Emit(OpCodes.Ldnull);116 }117 else118 {119 var parameters = ilOfMethod.DeclareLocal(typeof(object[]));120 ilOfMethod.Emit(OpCodes.Ldc_I4, methodParameterTypes.Length);121 ilOfMethod.Emit(OpCodes.Newarr, typeof(object));122 ilOfMethod.Emit(OpCodes.Stloc, parameters);123 124 for (var j = 0; j < methodParameterTypes.Length; j++)125 {126 ilOfMethod.Emit(OpCodes.Ldloc, parameters);127 ilOfMethod.Emit(OpCodes.Ldc_I4, j);128 ilOfMethod.Emit(OpCodes.Ldarg, j + 1);129 ilOfMethod.Emit(OpCodes.Stelem_Ref);130 }131 ilOfMethod.Emit(OpCodes.Ldloc, parameters);132 }133 134 // call Invoke() method of Interceptor135 ilOfMethod.Emit(OpCodes.Callvirt, typeof(Interceptor).GetMethod("Invoke"));136 137 // pop the stack if return void138 if (method.ReturnType == typeof(void))139 {140 ilOfMethod.Emit(OpCodes.Pop);141 }142 143 // complete144 ilOfMethod.Emit(OpCodes.Ret);145 }146 }147 }148 }
View Code

转载地址:http://uqodm.baihongyu.com/

你可能感兴趣的文章
为什么kafka使用磁盘而不是内存
查看>>
创立一个站点的前前后后(起因,域名,云平台,备案,CDN等等)(1)
查看>>
天朝git的使用
查看>>
什么是 HTTPS
查看>>
BPF and eBPF linux
查看>>
如何解决MySQL在高版本需要指明是否进行SSL连接问题
查看>>
[PAL算法说明]SAP HANA PAL线性回归预测分析Linear Regression算法说明LRREGRESSION
查看>>
JAVA学习课第二十八届(多线程(七))- 停止-threaded多-threaded面试题
查看>>
Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
查看>>
我的vim配置
查看>>
C#获取微信二维码显示到wpf
查看>>
时间戳和字符串之间的互相转换
查看>>
Android Studio导入第三方类库的方法
查看>>
oracle学习总结3
查看>>
041 添加分区以及分析函数和窗口函数
查看>>
The type Date is ambiguous
查看>>
MVC 5使用ViewBag(对象)显示数据
查看>>
python多版本共存
查看>>
ajax处理select下拉表单
查看>>
30+学习Web设计和开发的优质新鲜资源
查看>>