在上篇中咱们大概的讲解了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对象类型。