在上篇中咱們大概的講解了Model元數據的生成過程,並無對Model元數據自己和詳細的生成過程有所描述,本篇將會對詳細的生成過程進行講解,而且會對Model元數據自己的結構稍做講解,讀完本篇事後你將會對Model元數據的結構有個很清晰的印象。c#
什麼是Model元數據?框架
生成Model元數據的過程【一】ide
生成Model元數據的過程【二】函數
ModelMetaData的定義、詳解spa
Model元數據應用(經常使用特性應用)-1對象
Model元數據應用(自定義視圖模板)-2繼承
Model元數據應用(IMetadataAware接口使用)-3接口
還記得Model元數據系列篇的第一章裏的最後一幅圖嗎?ip
圖1ci
沒有錯,MVC框架根據咱們定義的視圖模型生成了一個Model元數據ModelMetadata(實際爲DataAnnotationsModelMetadata類型是繼承自ModelMetadata類型的,在下文中爲了更直觀的方便講解因此仍是用ModelMetadata類型來做介紹)。咱們來看一下ModelMetadata類型的定義:
代碼1-1
public class ModelMetadata { public ModelMetadata(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName); // // 摘要: // 獲取模型元數據對象的集合,這些對象描述模型的屬性。 // // 返回結果: // 用於描述模型屬性的模型元數據對象的集合。 public virtual IEnumerable<ModelMetadata> Properties { get; } // // 摘要: // 獲取模型的類型。 // // 返回結果: // 模型的類型。 public Type ModelType { get; } protected ModelMetadataProvider Provider { get; set; } …… }
只留了個構造函數和三個屬性,詳細的部分下篇會講到,構造函數中的第一個參數類型你們確定很熟悉,那就是上篇中講到的Model元數據生成程序,用來生成Model元數據(ModelMetadata類型)的,這樣的是把ModelMetadataProvider類型的引用設置到Model元數據的內部,也就是Provider屬性,這樣作是有目的的隨後就會講到,在其定義中還有個Properties屬性,類型你們都看到了是ModelMetadata類型的集合,這就是ModelMetadata類型關鍵的所在了,Properties屬性表示着當前ModelMetadata的所描述類型中的屬性元數據集合。
圖2
用前篇介紹過的Customer類型來作描述,對應着Customer類型的結構MVC框架也會生成對應的ModelMetadata類型結構,這裏捎帶提一下,對於Address屬性類型是Address類型這種屬於複雜類型,MVC框架會向下繼續生成就如同生成Customer類型同樣。
那麼這樣的結構是怎麼生成的呢?固然不用說了,是依靠Provider屬性也就是ModelMetadataProvider類型的引用來生成結構的,如圖3所示:
圖3
首先根據當前Model元數據ModelMetadata類型(對應的對象是Customer類型)中的Model屬性和ModelType屬性來做爲參數調用AssociatedMetadataProvider類型的GetMetadataForProperties()方法,這裏說一下ModelMetadata類型的Model屬性,表示着當前Model元數據所對應對象的值,也是用這個值來判斷是不是複雜類型的,ModelType屬性上面說過。
在GetMetadataForProperties()方法中會先根據自定義類型描述類型的GetProperties()方法來獲取當前對象是Customer類型的全部的屬性,而且封裝成屬性描述類型集合。
隨後根據獲取到的屬性描述類型集合,遍歷此集合而且根據遍歷中的單個屬性描述類型調用AssociatedMetadataProvider類型中的GetMetadataForProperty()方法,這裏要說的是第一個參數modelAccessor默認是Null的,第二個參數containerType是表示着當前Customer類型,第三個參數就是屬性描述類型了裏面包含着屬性類型的全部信息。有的朋友會問說明這些屬性作什麼,由於等下會說到第二個參數containerType的。
在AssociatedMetadataProvider類型中的GetMetadataForProperty()方法中,會根據PropertyDescriptor類型的參數獲取到當前屬性上全部描述信息(也就是那些特性類),好比當前的PropertyDescriptor類型是結構化Customer類型中的CustomerID,那圖3中AttrbuteList類型中就是包含着全部依附在這個屬性上的特性類。後續的生成過程仍是跟上篇的講解的同樣依舊的調用了AssociatedMetadataProvider類型的CreateMetadata(),只不過在AssociatedMetadataProvider類型中方法是抽象中,實際是由它的實現類DataAnnotationsModelMetadataProvider中的CreateMetadata()方法來完成的。
這裏你們可能會發現,在圖3中***框中的操做都是屬於遍歷中的操做,就是每次都會只會生成一個ModelMetadata類型實例而後最後合併在一塊兒返回出去。
還有要說的就是在圖3中***框中的每一個調用的函數都有個Type類型的containerType參數,這就是上面說過的Customer類型,而且在生成的ModelMetadata類型實例中賦值到ContainerType屬性,表示着新生成的ModelMetadata類型實例好比叫A,A中描述的信息就是Customer類型中的CustomerID屬性的全部信息,而A中的ContainerType屬性就是表示描述的CustomerID屬性是屬於哪一個類型的。
這裏還有要說的,就是在系統默認生成的時候,好比說視圖模型是Customer類型,那麼MVC框架只會生成一個ModelMetadata類型的實例假使它叫M,由於M自身並無本身檢測本身是否是複雜類型,因此M是不會調用提供器往下生成的,而是在外部要使用M了纔會去調用M中的函數檢測M是否是複雜類型而後往下生成,假使如今MVC框架中使用到了這個M可能就會調用檢測它自身的方法來檢查它是否是複雜類型,明顯的Customer類型是複雜類型,這個時候M會按照本篇描述的那樣依次的生成它所描述類型中的屬性,也只是僅限於這一層,有的朋友可能會問在Customer類型中Address屬性也是複雜類型,對的,可是M只會去生成Address屬性自己的ModelMetadata類型的實例,而不會去生成Address屬性的內部。
如今你們再看一次圖2,是否是有點清晰的感受。
(有哪位大神知道在MVC框架中是在哪裏調用ModelMetadata類型實例的自身檢測的?知道的告知一下小弟以身相許,找的頭破血流也沒找到,我相信是確定有的)
本篇結束,下篇中詳細介紹DataAnnotationsModelMetadataProvider類型中的CreateMetadata()方法,從這個方法進入,詳細的講解ModelMetadata對象類型。