NDoc Reloading: 泛型与反射(补)

(回过头看了一下前天晚上写的那篇随笔,发现确实很晕糊,至少文章里面只涉及了“泛型”,并没有涉及“反射”,题目是不确切的。所以写这一篇补充一下反射的东西。)

以下面的代码为例:

1。对该类所属的程序集(dll 或 exe)进行反射,可以得到表示泛型类 Abc 的 Type 对象 typeAbc。(对 Assembly.GetTypes 得到的 Type 数组枚举循环)

2。对于上一步得到的 typeAbc,IsGenericTypeDefinition 属性值应该是 true,按照 .NET Framework SDK 类库文档的样式(MSDN),对于泛型类型(准确地讲是“泛型类型定义”),在左侧目录树中、在类型页的天头,应该显示为“Abc 泛型类”。

3。在类型的首页中的“语法”块中,需要以 C#, VB.NET 等语言表示出该泛型类 Abc 的具体定义,即包含的每一个 parameter。使用 typeAbc.GetGenericArguments 方法,得到一个 Type[]。数组中的每一个 Type 代表一个泛型参数,既可能是形参 parameter,也可能是实参 argument。但是对于 Abc 来说,它是泛型类型定义,所以得到的每一个 Type 都应该是 parameter。泛型类型定义 Abc 只有一个形参,所以那个数组长度为1,唯一的一个 Type 假定用变量 typeParameter 存储。

4。对于上一步得到的 typeParamter,其 IsGenericParameter 属性值应为 true,其 Name 属性值就是该形参的名字“U”。

5。代码中,这个形参 U 具有两个约束条件,即1)必须是引用类型;2)必须实现 IComparable 接口。下面我们需要使用泛型得到这两个约束。

我们上次提到了五种泛型约束条件,需要分为两组,使用两种不同的方法才能得到。

5.1。typeParamter.GenericParamterAttributes 属性值是一个允许按位组合(具有 FlagsAttributes 属性)的枚举类型,查看 GenericParameterAttributes 枚举的文档可以得知,通过这个属性值,我们可以判断出 typeParameter 所代表的泛型形参 U,是否具有:1)引用类型约束(C# 代码写作 where U : class 的情形);2)非空值类型约束(C# 代码写作 where U : struct 的情形);3)默认构造函数约束(C# 代码写作 where U : new() 的情形)。

5.2。typeParameter.GetGenericParameterConstraints 方法得到一个 Type[],该数组中的每一个 Type 代表泛型形参 U 所具有的1)基类约束或裸约束,2)接口约束。对于我们的实际例子,typeParameter 调用该方法得到一个长度为 1 的 Type 数组,这个数组中的唯一一个 typeConstraint 对象(代表实际代码中的 IComparable 约束条件),其 IsClass 属性为 false,说明它是一个接口约束。(这里,typeConstraint 其实就等于 typeof(IComparable)。)

总结上面的反射步骤为下图:

接下来简单写一下对于 Abc 泛型类中 Xyz 属性的反射过程:

1。同上面的1。

2。typeAbc.GetProperties 方法得到 PropertyInfo 的数组,循环每一个 PropertyInfo。假定变量 propertyXyz 存储 Xyz 属性的那个 PropertyInfo。

3。propertyXyz.PropertyType 属性可以得到、表示该属性类型的 Type 对象:typePropertyType。(对比实际代码可以知道,此 Type 对象是一个泛型类型,是一个开放构造类型,而且有嵌套现象。)

4。对 typePropertyType 类型,调用其 GetGenericTypeDefinition 方法得到其基础类型,可以知道它是一个 System.Collections.Generics.Dictionary  泛型类型。

5。然后对 typePropertyType 执行类似前面的步骤 3、4: GetGenericArguments 得到 typeArg1 和 typeArg2 两个 Type 组成的数组。

6.1。typeArg1 是一个比较普通的类型(IsGenericType = false),可以确定出 Dictionary 泛型类型的第一个实参 string。

6.2.1。对于 typeArg2,虽然 IsGenericType = false,但因为 IsArray = true,首先确定它表示一个数组。对于数组类型,需要调用 GetElementType 方法取得数组元素的类型 typeArg2ArrayElement。

6.2.2。typeArg2ArrayElement.IsGenericType = true,需要重复步骤 4、5、6,分别确定其泛型定义是 System.Collections.Generics.List。稍微特殊的是,唯一的那个泛型参数(实际代码中的那个 U),其 IsGenericParameter = true,它并不是一个确定的类型,而是一个 parameter。

点击这里下载完整的示意图形,Excel 格式)


posted on 2006-09-10 15:51  破宝  阅读(184)  评论(0编辑  收藏  举报

导航