本节的源码本人已托管于Coding上:点击查看。
本文实验环境:VS 2017 Community。
要有效地使用AOP,AOP自己的架构及其对大代码架构的影响是要理解的重要概念。 当你在设计和实现一个架构时,PostSharp可以快速且自动地帮助你在编译时识别错误。
直到现在,我们一直在狭隘地研究PostSharp和AOP:一次一个切面和一个类。现在从架构师的角度, 来看看PostSharp是如何与整个系统配合在一起的。 PostSharp包含了使架构师工作更简单的工具,以及确保各切面本身都具有良好架构的工具。
在某些时候关于PostSharp,你可能关心的一件事就是我的所有例子都是将特性放在独立的方法和属性上,这也许看起来很繁琐和重复,如果你在一个大的代码库中也必须这么做的话,确实很重复且繁琐。 幸运的是,PostSharp并不要求你始终这样做。 接下来会看看多播切面特性的方式,以便我们可以重用切面且不需要太多的特性重复。
因为PostSharp是作为编译时工具实现的,它为我们开辟了编写可以在正常编译时间之后立即运行的代码的大门。 我们可以利用这个机会编写代码,用于验证:切面正在正确的地方使用,并且不会在运行时引起问题,以及整个项目的结构和架构。 这种方法会使得早早发现问题(或者我喜欢称之为失败更快,或最早失败)。
我们也将借此机会执行切面的初始化。 如果你有昂贵的操作(如使用Reflection),那么最好地让它在构建期间就完成不要等到运行时。
编译时初始化和验证
我们来看一下上一章的PostSharp构建过程,看看它如何适应普通的.NET构建过程。 回想一下,你有编译时阶段(代码编译成CIL)和运行阶段(其中CIL被编译为及时被执行的机器指令),见下图。 编译时的AOP工具,如PostSharp,又增加了一个步骤(后编译器),并在编译之后但在执行之前修改CIL。
PostSharp为你编写的每个方面执行几个步骤。 每个方面都是使用aspect的构造函数实例化。 PostSharp然后执行验证步骤(调用你切面的CompileTimeValidate方法)来检查切面是否正在正确使用。 然后PostSharp执行一个初始化步骤(调用切面的CompileTimeInitialize方法)来执行任何昂贵的计算,而不是等到运行时。 最后,PostSharp会获得这个切面实例并将其序列化(到二进制流),以便可以稍后在运行时进行反序列化和执行。
下面看一下后期编译器的详细图解,对应上面这段话的解释:
本节重点介绍该过程的验证和初始化步骤。 直到这个章节中,为了保持简单,在例子中,我没有定义任何CompileTimeValidate或CompileTimeInitialize代码。 所有这些步骤仍然会执行,但是因为我们没有定义CompileTimeValidate