C# 使用Emit实现动态AOP框架 (一)
最近需要有一个完全自主的基于c#语言的aop框架,查了一下资料实现方式主要分为:静态织入和动态代理,静态织入以postshop为代表,而动态代理又分为:
1、普通反射
2、emit反射
3、微软提供的.net remoting和realproxy
(微软官方例子)
总体来说静态织入速度最快,普通反射最慢,而.net remoting和realprox实现起来又相对较复杂。而emit速度居中,同时其一次生成后,将结果序列化,速度也并不慢,同时和原有类并没有紧密耦合,通过外部配置文件可以方便的控制要进行代理的类型、方法和属性,其缺点是被代理的方法、属性必须为virtual类型。
一、被代理类和代理类
被代理类,是我们正常使用的类,里边是原有的业务逻辑,只要在被代理方法上申明上相应的切面特性就行了,使用起来比较简单;如下
1 public class aoptest 2 { 3 4 public aoptest() 5 { 6 name = "小明"; age = 10; 7 } 8 9 public aoptest(string name, int age) 10 { 11 name = name; age = age; 12 } 13 14 [log] 15 public virtual string name { get; set; } 16 17 [log] 18 public virtual int age { get; set; } 19 20 [log] 21 public virtual int nyearlater(int a) 22 { 23 int larter = age + a; 24 25 return larter; 26 } 27 }
代理类是aop框架自动生成的类,使用反编译工具我们可以看到,它比被代理类多了切面上下文声明(aspectcontent)和相应的切面特性对象声明,在被代理类的方法执行前后,相应切面特性调用onentry、onexit执行相关操作,如日志、参数验证、权限验证等等aop功能,其中aspectcontext是onentry、onexit调用参数,如下:
public class aoptest_proxy : aoptest { public override string name { get { object[] args = new object[0]; aspectcontext aspectcontext = new aspectcontext(this, "get_name", args); logattribute logattribute = new logattribute(); logattribute.onentry(aspectcontext); string name = base.name; aspectcontext.result = name; logattribute.onexit(aspectcontext); return name; } set { aspectcontext context = new aspectcontext(this, "set_name", new object[] { value }); logattribute logattribute = new logattribute(); logattribute.onentry(context); base.name = value; logattribute.onexit(context); } } public override int age { get { object[] args = new object[0]; aspectcontext aspectcontext = new aspectcontext(this, "get_age", args); logattribute logattribute = new logattribute(); logattribute.onentry(aspectcontext); int age = base.age; aspectcontext.result = age; logattribute.onexit(aspectcontext); return age; } set { aspectcontext context = new aspectcontext(this, "set_age", new object[] { value }); logattribute logattribute = new logattribute(); logattribute.onentry(context); base.age = value; logattribute.onexit(context); } } public aoptest_proxy(string name, int age) : base(name, age) { } public override int nyearlater(int num) { aspectcontext aspectcontext = new aspectcontext(this, "nyearlater", new object[] { num }); logattribute logattribute = new logattribute(); logattribute.onentry(aspectcontext); int num2 = base.nyearlater(num); aspectcontext.result = num2; logattribute.onexit(aspectcontext); return num2; } }
二、测试方法
public static void test() { try { aoptest withpara = dynamicproxy.create<aoptest>("lxl", 10); ; withpara.nyearlater(10); console.writeline("done..."); } catch (exception ex) { console.writeline(ex.message); } }
测试方法中:aoptest withpara = dynamicproxy.create<aoptest>("lxl", 10); ,生成一个代理对象,其他就正常使用就可以了。
调用测试方法执行结果如下:
log onentry:set_name(lxl) log onexit: set_name log onentry:set_age(10) log onexit: set_age log onentry:nyearlater(10) log onentry:get_age() log onexit: get_age result: 10 log onexit: nyearlater result: 20 done...
通过结果可以看到 属性name、age的set方法,nyearlater方法,以及age属性的get方法都实现了日志记录。下边将分几篇来详细介绍dynamicproxy类的实现。欢迎大家多多指正、交流。
下一篇: phpBB BBcode处理的漏洞