• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

在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

下载完整代码


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
c#获取电脑运行状态(cpu,内存,网络,系统运行时间)发布时间:2022-07-14
下一篇:
C#创建WebApi项目发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap