熟悉Castle的朋友一定清楚:在Castle体系中,有一个叫Aspect#的子项目。Aspect#是一个AOP的框架,在这篇文章中,我并不打算直接开始讲Aspect#,因为Aspect#的封装过于完善,不太利于用来讲述AOP的具体实现细节。其实Aspect#的基础是DynamicProxy,所以,我们先来讲讲DynamicProxy。
在很多朋友的眼中,AOP似乎是一个很神秘的东西,其实在我看来,AOP的本质就是对一切操作行为的拦截,在.Net中,AOP的本质更简单,纯粹是对方法的拦截。为什么这么说呢?因为在.Net中,一切的操作都是方法调用:事件的 “+=” 及 “-=”最终被转换为 Addxxxx(...),Removexxxxx(...)类型的方法;属性的 get/set 过程也被转换为 getxxxxxx(...),setxxxxxx(...)类型的方法;而方法的本身就更不用说了。
方法拦载的实现的原理是动态构建类型,动态构建类型的功能是由“mscorlib.dll” 这个.Net核心的程序集提供的,有兴趣的朋友可以详细研究一下这个程序集的“System.Reflection.Emit”命名空间的内容。由于方法的拦载是动态构建类型,所以我们在拦截类方法时,可以采取用动态构造类的方式,从该类继承一个子类,重载并改写类中需要拦截的方法。因此,我们不难理解,为什么在Castle 的 AOP中实现对类方法的拦截,都需要该类中的可被拦载的方法都是能够被子类重载的(override)。
说了这么多,让我们来写一个简单的程序来演示在 Castle 中AOP 的基础吧,先看看一个简单的类型:
- using System;
- namespace Unit6
- {
- public class Person
- {
- public virtual void SayHello()
- {
- Console.WriteLine("Hello!");
- }
- public virtual void SayName()
- {
- Console.WriteLine("My Name is Roger");
- }
- public void SayOther()
- {
- Console.WriteLine("Yes,I do!");
- }
- }
- }
这个类型没什么好说的,只是输出一些字符串而以。惟一需要注意的是:前两个方法都是虚方法,而“SayOther”不是虚方法,即是说“SayOther”不可以用一般的方式重载。
再来看看方法拦载器的代码:
- using System;
- using Castle.DynamicProxy;
- namespace Unit6
- {
- public class SimpleInterceptor : StandardInterceptor
- {
- protected override void PreProceed(
- IInvocation invocation, params object[] args)
- {
- Console.WriteLine("Simple Interceptor Running! Method Name:{0}."
- , invocation.Method.Name);
- base.PreProceed(invocation, args);
- }
- }
- }
Castle DynamicProxy提供了一个标准的方法拦截器,在一般的情况下,从这个标准的拦截器继承便可以完成大部分方法拦载上面的需求。StandardInterceptor中提供了三个可重载的方法:
- PreProcced,在进入拦截的方法之前调用。
- PostProcced,在拦截的方法运行完成后调用。
- Intercept,在拦截的方法返回时调用
正如上面的代码所展示的,我们会在被拦载的方法调用之前,输出相关的一些信息,接下来我们来看看如何使用这个写好的拦截器
- using System;
- using Castle.DynamicProxy;
- namespace Unit6
- {
- internal class Program
- {
- private static void Main()
- {
- SimpleInterceptor interceptor = new SimpleInterceptor();
- ProxyGenerator generator = new ProxyGenerator();
- Person person = (Person) generator.
- CreateClassProxy(typeof (Person), interceptor);
- Console.WriteLine("Current Type:{0},Base Type:{1}",
- person.GetType(), person.GetType().BaseType);
- Console.WriteLine();
- person.SayHello();
- Console.WriteLine();
- person.SayName();
- Console.WriteLine();
- person.SayOther();
- Console.ReadLine();
- }
- }
- }
在上面的代码中,ProxyGenerator其实是一个动态的类型构造器,它依据Person类型,并加入相应的拦载器构造出了一个新的类型,我们来查看一下运行输出:
根据输出的第一行,我们可以知道,ProxyGenerator构造了一个新的类型,这个类型继承自Person,由于这个类型的SayOther方法不可以被子类重载,所以这个方法无法被拦截。