• 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 }
    复制代码

    运行结果

    完整代码

     View Code

    下载完整代码

  • 相关阅读:
    ssh免密登录
    jdk安装
    jq选择器
    使用<button></button>标签
    mysql连接字符串
    如何把maven项目转成web项目
    pl/sql连接远程oracle
    Oracle 存储过程
    SQL Server存储过程
    MySQL存储过程
  • 原文地址:https://www.cnblogs.com/twinhead/p/9161483.html
Copyright © 2020-2023  润新知