NDoc Reloading: 泛型与反射

NDoc Reloading 首先面对的课题就是 .NET 2.0 中新增的泛型类型、泛型方法、可空类型等新增功能。由于可空类型应该可以算作泛型类型的一个特例,这里就不再多说了。

对于泛型类型,在 Type.IsGenericType 属性的 .NET 文档中,微软告诉我们一些术语,这里简单说明一些:

1)泛型类型定义(Generic Type Definition),就是最初定义该泛型类型的那个类型,比如 List<T>,Dictionary<TKEY, TValue> 这些类型。

2)上述这些类型括号中的这些 T, TKey, TValue 是泛型类型形参(Parameter)。

3)在实际运用 List<T> 或者 Dictionary<TKEY, TValue> 时,总是需要将这些 Parameters 指定为特定的类型,比如 List<String>, Dictionary<String, int>,则这些处于 Parameter 位置上的类型(string, int),就是泛型类型实参(Arguments)。

4)如果泛型类型定义中的所有 Parameters 都被替换为 Arguments 的话,就被称为封闭构造类型

5)否则,只要还有任何一个 Parameter 没有被替换,就是开放构造类型

泛型方法,与泛型类型类似,也有类似的几个术语。(参见 System.Reflection.MethodBase.IsGenericMethod 的文档中)

在研究这个问题之前,我从来没有区分过 Parameter 和 Argument 这两个英语词,都认为是“参数”,这次总算明白,Parameter 是“形参”,Argument 是“实参”。我认为搞清楚形参和实参,对理解较复杂的泛型是很重要的。.NET Framework SDK 的文档在这方面做的不够好,很多地方都翻译为“参数”,有时就需要对照英文原文来区分到底是 Parameter 还是 Argument。

上面所说的都是简单的情形。复杂的情况比如说嵌套:对于一个 Dictionary<TKey, TValue>,TKey 指定为 string,TValue 指定为另一个 List<T> 类型,就构成了一个嵌套的 Dictionary<String, List<T>>。

再比如说,Parameter 的相对性:这点不太好理解。比如 Type.GenericParameterPosition 属性中给出个这个例子:

public class B<T, U> { }
public class A<V>
{
    public B<V, X> GetSomething<X>()
    {
        return new B<V, X>();
    }
}

其中的红色部分 B<V, X>,V 的 GenericParameterPosition = 0,因为它是其所属的泛型类 A<V> 的第一个形参;X 的 GenericParameterPosition 也 = 0,因为它是其所属的泛型方法 GetSomething<X> 的第一个形参。而 X 对于泛型方法 GetSomething<X> 来说,其实是一个“已经确定了的”类型。

关于泛型,还需要考虑约束的问题,每一个泛型形参,可以有五种类型的约束约束,即:class,struct,new(), 基类型约束,接口约束,裸约束。(详见 C# 语言参考)其中裸约束可以认为是基类型约束的一个特例。

NDoc 的工作原理大体是:先对程序集进行反射,收集所需要的信息,生成一个中间 XML 格式;然后交给 XSLT 转换为 HTML 页面。

网络中目前有几个 NDoc 修改版,试图解决对泛型的支持(比如:Jonas 的版本),但基本上都是在原有 XML 格式的基础上,作了一些 HACK。可以说只能应付简单意义的泛型类型,不能应对实际运用中可能出现的复杂情形。

为了从根本上全面支持泛型,就必须修改这个 XML 格式,让它在每个角落都支持泛型。在这个 XML Scheme 里面,我首先添加了一个名为 type 的 Complex Type,如下图所示:

以我目前的“想象力”,这个图应该可以包容 99.99% 可能出现的情况了吧?

好了,先写这么多,找到了 NinputerVBF 类库。这个库中大量使用了泛型,而且 Ninputer 的注释也比较完备。我将用这个类库作为检验 NDoc 是否全面支持泛型的测试实例。另外,我也在阅读 Ninputer 的泛型“专题”,不断的矫正自己的思路。

posted on 2006-09-07 21:29  破宝  阅读(194)  评论(0编辑  收藏  举报

导航