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 }

运行结果

完整代码
C#使用Emit构造拦截器动态代理类的更多相关文章
- 秒懂C#通过Emit动态生成代码 C#使用Emit构造拦截器动态代理类
秒懂C#通过Emit动态生成代码 首先需要声明一个程序集名称, 1 // specify a new assembly name 2 var assemblyName = new Assembly ...
- 【Java EE 学习 75 下】【数据采集系统第七天】【二进制运算实现权限管理】【使用反射初始化权限表】【权限捕获拦截器动态添加权限】
一.使用反射动态添加权限 在该系统中,我使用struts2的时候非常规范,访问的Action的形式都是"ActionClassName_MethodName.action?参数列表" ...
- .Net基础——程序集与CIL HttpClient封装方法 .Net Core 编码规范 C#中invoke和beginInvoke的使用 WebServeice 动态代理类
.Net基础——程序集与CIL 1. 程序集和CIL: 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll ...
- spring AbstractBeanDefinition创建bean类型是动态代理类的方式
1.接口 Class<?> resourceClass 2.获取builder BeanDefinitionBuilder builder = BeanDefinitionBuilder. ...
- WebServeice 动态代理类
1, webservice是什么? 是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序 ...
- CGLIB 和 JDK生成动态代理类的区别(转)
文章转自http://luyuanliang.iteye.com/blog/1137292 AOP 使用的设计模式就是代理模式,是对IOC设计的补充.为了扩展性,往往会加上反射,动态生成字节码,生成代 ...
- java代理模式及动态代理类
1. 代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 ...
- 初看Mybatis 源码 (二) Java动态代理类
先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...
- Alibaba Java诊断工具Arthas查看Dubbo动态代理类
原创/朱季谦 阅读Dubbo源码过程中,会发现,Dubbo消费端在做远程调用时,默认通过 Javassist 框架为服务接口生成动态代理类,接着再去调用代理类实现远程接口调用.在阅读这部分源码时,最后 ...
随机推荐
- CFtpConnection Class
CFtpConnection Class 1.链接http://technet.microsoft.com/zh-cn/office/2kywsafk(v=vs.80) 2.测试ftp可以用这个地 ...
- cu命令
选项: -b:仅显示行中指定直接范围的内容: -c:仅显示行中指定范围的字符: -d:指定字段的分隔符,默认的字段分隔符为“TAB”: -f:显示指定字段的内容: -n:与“-b”选项连用,不分割多字 ...
- Centos6.8下卸载软件(以Mysql为例)
1 删除Mysql yum remove mysql mysql-server mysql-libs mysql-server; find / -name mysql 将找到的相关东西delete掉 ...
- delete指针以后应赋值为NULL
delete p后,只是释放了指针中存放的地址中的内存空间.但是指针变量p仍然存在(即指针p本身所占有的内存),且p中存放的地址还是原来的地址. 例如: 对一个非空指针delete后,若没有将p赋为N ...
- HNU 2015暑期新队员训练赛2 B Combination
先转化出求 Cnr中有多少奇数 其实就是 (n 的二进制数中 1 的个数为 k ,则这个奇数为 2 ^ k) 因为数很大, 故要快速求出区间的奇数 然后求 0 – low-1 的奇数, 0- high ...
- python学习第9-10天,函数。
函数初识 为什么要使用函数? 函数最重要的目的是方便我们重复使用相同的一段程序. 将一些操作隶属于一个函数,以后你想实现相同的操作的时候,只用调用函数名就可以,而不需要重复敲所有的语句. 函数的定义与 ...
- Js -----后台json数据,前端生成下载text文件
需要引入 <script src="/assets/libs/single_file/jquery.min.js"></script> <script ...
- Laravel 5.2服务----用户验证Auth相关问题
关于laravel的auth()用户认证这一块,面前我也是,有用到,有碰到什么问题我就记录下来. 手动认证用户 <?php namespace App\Http\Controllers; use ...
- 根据CAS协议写的简单的SSO框架
前言: 考虑到现在分布式应用都不可或缺的一个重要部分:单点登录,决定花点时间去学下.本来想直接上现成的CAS框架的,初步的了解了一下后,觉得这个太庞大了,而且不好定制,要完全深度用起来也没那么简单 ...
- [转]PhpStorm快捷键大全
1 前言 PhPStorm 是 JetBrains 公司开发的一款商业的 PHP 集成开发工具,PhpStorm可随时帮助用户对其编码进行调整,运行单元测试或者提供可视化debug功能.Phpstro ...