为了账号安全,请及时绑定邮箱和手机立即绑定

C#用Emit构造拦截器动态代理类

标签:
C#

在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 Command
2 {
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<T>() 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<T>(typeBuilder);
 18 
 19     var t = typeBuilder.CreateType();
 20 
 21     return Activator.CreateInstance(t) as T;
 22   }
 23 
 24   private static void InjectInterceptor<T>(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<Command>();
 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<Command>();
 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<T>() 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<T>(typeBuilder);
 63 
 64       var t = typeBuilder.CreateType();
 65 
 66       return Activator.CreateInstance(t) as T;
 67     }
 68 
 69     private static void InjectInterceptor<T>(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 T
109         ilOfMethod.Emit(OpCodes.Newobj, typeof(T).GetConstructor(new Type[0]));
110         ilOfMethod.Emit(OpCodes.Ldstr, method.Name);
111 
112         // build the method parameters
113         if (methodParameterTypes == null)
114         {
115           ilOfMethod.Emit(OpCodes.Ldnull);
116         }
117         else
118         {
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 Interceptor
135         ilOfMethod.Emit(OpCodes.Callvirt, typeof(Interceptor).GetMethod("Invoke"));
136 
137         // pop the stack if return void
138         if (method.ReturnType == typeof(void))
139         {
140           ilOfMethod.Emit(OpCodes.Pop);
141         }
142 
143         // complete
144         ilOfMethod.Emit(OpCodes.Ret);
145       }
146     }
147   }
148 }
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消