码迷,mamicode.com
首页 > Windows程序 > 详细

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

时间:2018-06-09 23:15:43      阅读:228      评论:0      收藏:0      [点我收藏+]

标签:概念   const   lse   att   cep   too   封装   close   pop   

在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 }
技术分享图片

运行结果

技术分享图片

完整代码

技术分享图片 View Code

下载完整代码

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

标签:概念   const   lse   att   cep   too   封装   close   pop   

原文地址:https://www.cnblogs.com/twinhead/p/9161483.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!