XAF新手入門 – 類型子系統(Types Info Subsystem)
類型子系統概述
類型子系統是XAF的核心概念,但我們平時卻很少關注它,它集中存儲了模組中的類型,它是生成應用程式模型(Application Model)的基礎,它與XAF中其它的概念都有所關聯,了解它可以使我們加深對XAF的理解。
類型子系統是什麼
第一次接觸類型子系統的小夥伴,應該感覺它與.NET中的類型系統是相似的,並且它中的一些介面與類與.NET類型系統也是對應的,如:ITypeInfo,IMemberInfo,IAssemblyInfo,是不是感覺很熟悉,其實XAF類型子系統就是對.NET類型系統的一個包裝,並加入了一些XAF特有的功能,下面是XafApplication的構造函數。
TypesInfo是ITypesInfo的唯一派生類,它是類型子系統的核心,它提供了類型子系統的大部分功能,它也是類型子系統的代名詞。
XafApplication構造函數中唯一需要傳遞的參數就是ITypesInfo,從這點也可以看出類型子系統在XAF中的重要性。TypesInfo的實例是通過XafTypesInfo以單例形式提供的(XafTypesInfo.Instance),需要注意在整個XAF項目中只有這一個TypesInfo實例,在不同的平台(WinForm與Blazor)下也是一樣的,下面是XafTypesInfo創建TypesInfo實例的方法。
在XAF項目中的任何地方,你都可以直接使用XafTypesInfo.Instance訪問到TypesInfo實例,在Blazor中ITypesInfo已被注入到容器中,你可以通過ServiceProvider.GetService<ITypesInfo>()獲取TypesInfo實例,實際也是指向XafTypesInfo.Instance。
使用過XAF一段時間的小夥伴應該都知道XAF模組中的一些資源(BusinessObject、Controller等)都是通過反射(Reflection)方式進行收集的,而反射是有一定性能損耗的,如果在每次需要的時候都反射一次,系統的性能損耗會很大。TypesInfo會在XAF初始化時(Application.Setup),對模組(XAF模組)類庫中的類型進行收集並快取起來,不會對非模組類庫進行收集,除非在Module類中進行了導出(如何導出非本模組中的類型,會在後續的章節中進行介紹)。
TypesInfo收集的類型(System.Type)會通過TypeInfo進行包裝,類型的公共欄位或屬性是通過IMemberInfo進行包裝,同時TypesInfo也提供了更加豐富的功能。在還沒有深入了解TypesInfo之前,你可以簡單的將TypesInfo理解為是對模組中類型的快取,並提供了一些對快取類型的操作方法(如:創建、更新、查找等)。
.NET中的反射常用於框架的開發,框架可以通過反射收集類型的資訊,並通過這些類型資訊輔助完成一些功能,XAF也是一個開發框架,TypesInfo承擔了類型資訊收集的角色,理所當然成了XAF的類型中心,其它功能模組就可以通過TypesInfo訪問到自己所需的類型。
應用程式模型(Application Model)就是基於TypesInfo創建了模型中的Controller、Action、View等節點,關於應用程式模型,會在後面章節講解。
DevExpress.ExpressApp.DC命名空間下包含了XAF類型子系統的主要類型,大家可以通過ILSpy等類似工具查看該命名空間下類型之間的依賴關係。
說一個小插曲,DC在XAF中就是DomainCompnent(域組件),ApplicationModel是基於DomainComponent的,BusinessObject中的NonPersistentObject也是基於DomainComponent的,在更早之前XPO有一個基於DomainComponent自動生成PersistentObject的功能(現在它已被棄用了),在這些DomainComponent當中,感覺ApplicationModel與XPO的DomainComponent很類似,都是基於介面的,NonPersistentObject只借用了DomainComponent這個概念,使用了DomainComponentAttribute,但在工作原理上與前兩個有很大的區別。由於官方文檔中沒有關於它們之間關係的描述,以上的觀點更多的只是個人的見解,有熟悉的小夥伴可以在評論區說說你的看法。
XAF是基於模型驅動的,模型是XAF的主線,模型在XAF中稱為BusinessObject(有時也簡稱為BO),雖然TypesInfo存儲了模組中的類型,但它大部分功能都是針對BusinessObject的。
TypesInfo實例中包含了一個PersistentTypes屬性,雖然名字顯示的是持久化類型,但其實它也包含了非持久化類型,而PersistentTypes的數據是由IEntityStore提供,TypesInfo中包含多個IEntityStore,下面是PersistentTypes的源碼。
PersistentTypes中所有的類型都會在ApplicationModel中創建一個View節點。
官方文檔中沒有關於IEntityStore的介紹,與其相似的還有一個ITypeInfoSource,官方文檔中也沒有介紹,通過查看源碼,大體知道了它們的含義,它們都有多個派生類,大部分都是重合的。雖然TypesInfo包含了所有類型,但都是放在一個快取當中的,類型也有不同的分類,主要是想將持久化類型(XPO中的類型)與非持久化類型進行單獨的存儲,在這裡持久化類型與非持久化類型它們統稱為Entity,而派生自IEntityStore的類,就是用於分別存儲不同類型的Entity,例如:XpoTypeInfoSource是負責存儲XPO中的類型,NonPersistentTypeInfoSource是負責存儲非持久化對象類型(NonPersistentObject),IEntityStore主要負責Entity類型的存儲,而ITypeInfoSource在負責類型存儲的同時,也提供了對類型的操作,你可以通過ILSpy工具查看它們的更多內容。
下面是TypesInfo的創建方法,前面已介紹過
在上面的程式碼中,我們可以看到TypesInfo會默認添加一個NonPersistentTypeInfoSource實例,在XAF初始化的過程中,還會添加一個XpoTypeInfoSource實例(這是默認情況下,如果你的系統中存在多個ObjectSpaceProvider,還會添加其它的)。
類型子系統能做什麼
通過前面的介紹,我們知道TypesInfo可以為XAF功能模組提供所需的類型,也可以稱為XAF的類型中心,官網提供了一個訪問示例://docs.devexpress.com/eXpressAppFramework/113224/business-model-design-orm/types-info-subsystem/access-business-object-metadata
TypeInfo可以對成員(IMemberInfo)添加或修改,我們可以通過它來實現自定義TypeInfo,XAF提供了多種自定TypesInfo的方式,但我們一般會選擇是在Module或Controller中,在Module或Controller中都是重寫CustomizeTypesInfo方法,結果都是一樣的,在選擇上如果只會在某個Controller中調用,這樣自定義與調用都放在一個Controller中會更加的直觀,當然在Module中自定義會更加統一,這樣你做了哪些自定義在Module中就能看到,這兩種方式沒有優劣,Controller中的自定義也只會調用一次。官網提供了一個CustomizeTypesInfo示例://docs.devexpress.com/eXpressAppFramework/113583/business-model-design-orm/types-info-subsystem/use-metadata-to-customize-business-classes-dynamically
寫在最後
本篇文章主要介紹了類型子系統的概念及在XAF中的作用,與其它XAF概念的結合及應用會在後面的章節中介紹。TypesInfo還有很多有用的屬性與方法,想更加深入的了解,你還需要查閱官方文檔,文檔不全的可以結合源碼。