zoukankan      html  css  js  c++  java
  • C#使用Emit构造拦截器动态代理类

    在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 }
    View Code

    下载完整代码

  • 相关阅读:
    Linux应用程序的地址布局
    C/C++中的内存四区!
    编程语言的选择重不重要?对普通人而言,反其道而行更可靠!
    【C语言程序设计】C语言求最大公约数(详解版)!
    【C语言程序设计】C语言求最小公倍数(详解版)!
    【C语言程序设计】C语言求定积分!腻不腻害!
    你是因为什么而当程序员啊!网友们众说纷纭,从装b到被逼,理由层出不穷!
    华为程序员爆料:主动离职,公司竟也给n+1,到手15万,华为真良心!
    【C语言程序设计】C语言整数逆序输出程序!
    copy 和 mutablecopy
  • 原文地址:https://www.cnblogs.com/gaochundong/p/csharp_emit_create_interceptor_proxy.html
Copyright © 2011-2022 走看看