本節(jié)的源碼本人已托管于Coding上:點(diǎn)擊查看。
本文實(shí)驗(yàn)環(huán)境:VS 2017 Community。
要有效地使用AOP,AOP自己的架構(gòu)及其對大代碼架構(gòu)的影響是要理解的重要概念。 當(dāng)你在設(shè)計(jì)和實(shí)現(xiàn)一個(gè)架構(gòu)時(shí),PostSharp可以快速且自動(dòng)地幫助你在編譯時(shí)識(shí)別錯(cuò)誤。
直到現(xiàn)在,我們一直在狹隘地研究PostSharp和AOP:一次一個(gè)切面和一個(gè)類。現(xiàn)在從架構(gòu)師的角度, 來看看PostSharp是如何與整個(gè)系統(tǒng)配合在一起的。 PostSharp包含了使架構(gòu)師工作更簡單的工具,以及確保各切面本身都具有良好架構(gòu)的工具。
在某些時(shí)候關(guān)于PostSharp,你可能關(guān)心的一件事就是我的所有例子都是將特性放在獨(dú)立的方法和屬性上,這也許看起來很繁瑣和重復(fù),如果你在一個(gè)大的代碼庫中也必須這么做的話,確實(shí)很重復(fù)且繁瑣。 幸運(yùn)的是,PostSharp并不要求你始終這樣做。 接下來會(huì)看看多播切面特性的方式,以便我們可以重用切面且不需要太多的特性重復(fù)。
因?yàn)镻ostSharp是作為編譯時(shí)工具實(shí)現(xiàn)的,它為我們開辟了編寫可以在正常編譯時(shí)間之后立即運(yùn)行的代碼的大門。 我們可以利用這個(gè)機(jī)會(huì)編寫代碼,用于驗(yàn)證:切面正在正確的地方使用,并且不會(huì)在運(yùn)行時(shí)引起問題,以及整個(gè)項(xiàng)目的結(jié)構(gòu)和架構(gòu)。 這種方法會(huì)使得早早發(fā)現(xiàn)問題(或者我喜歡稱之為失敗更快,或最早失?。?/p>
我們也將借此機(jī)會(huì)執(zhí)行切面的初始化。 如果你有昂貴的操作(如使用Reflection),那么最好地讓它在構(gòu)建期間就完成不要等到運(yùn)行時(shí)。
編譯時(shí)初始化和驗(yàn)證
我們來看一下上一章的PostSharp構(gòu)建過程,看看它如何適應(yīng)普通的.NET構(gòu)建過程。 回想一下,你有編譯時(shí)階段(代碼編譯成CIL)和運(yùn)行階段(其中CIL被編譯為及時(shí)被執(zhí)行的機(jī)器指令),見下圖。 編譯時(shí)的AOP工具,如PostSharp,又增加了一個(gè)步驟(后編譯器),并在編譯之后但在執(zhí)行之前修改CIL。
PostSharp為你編寫的每個(gè)方面執(zhí)行幾個(gè)步驟。 每個(gè)方面都是使用aspect的構(gòu)造函數(shù)實(shí)例化。 PostSharp然后執(zhí)行驗(yàn)證步驟(調(diào)用你切面的CompileTimeValidate方法)來檢查切面是否正在正確使用。 然后PostSharp執(zhí)行一個(gè)初始化步驟(調(diào)用切面的CompileTimeInitialize方法)來執(zhí)行任何昂貴的計(jì)算,而不是等到運(yùn)行時(shí)。 最后,PostSharp會(huì)獲得這個(gè)切面實(shí)例并將其序列化(到二進(jìn)制流),以便可以稍后在運(yùn)行時(shí)進(jìn)行反序列化和執(zhí)行。
下面看一下后期編譯器的詳細(xì)圖解,對應(yīng)上面這段話的解釋:
本節(jié)重點(diǎn)介紹該過程的驗(yàn)證和初始化步驟。 直到這個(gè)章節(jié)中,為了保持簡單,在例子中,我沒有定義任何CompileTimeValidate或CompileTimeInitialize代碼。 所有這些步驟仍然會(huì)執(zhí)行,但是因?yàn)槲覀儧]有定義CompileTimeValidate