.Net泛型类的学习首先我们来看看什么是.Net泛型类?带有“类型参数”的类称为“泛型类”。那么如果使用.Net泛型类,则可为每个这样的参数提供“类型变量”,从而从.Net泛型类生成一个“构造类”。之后可以声明类型为构造类的变量,创建构造类的实例,并将它分配给该变量。除类以外,您还可以定义和使用泛型结构、接口、过程和委托。下面我们就来看看.net泛型类的一些声明和以及.Net泛型类创建的实例情况。
.Net泛型类声明
泛型类声明是一种类的声明,它需要提供类型实参才能构成实际类型。
类声明可以有选择地定义类型形参:
- class-declaration:
- attributesopt
- class-modifiersopt
- class identifier
- type-parameter-listopt
- class-baseopt
- type-parameter-constraints-clausesopt
- class-body ;opt
只有提供了一个 type-parameter-list,才可以为这个类声明提供 type-parameter-constraints-clauses。
提供了 type-parameter-list 的类声明是一个泛型类声明。此外,任何嵌套在泛型类声明或泛型结构声明中的类本身就是一个泛型类声明,因为必须为包含类型提供类型形参才能创建构造类型。
除了明确指出的地方外,泛型类声明与非泛型类声明遵循相同的规则。泛型类声明可嵌套在非泛型类声明中。
使用构造类型 (constructed type)引用泛型类。给定下面的泛型类声明
- class List﹤T﹥ {}
List﹤T﹥、List﹤int﹥ 和 List﹤List﹤string﹥﹥ 就是其构造类型的一些示例。使用一个或多个类型形参的构造类型(例如 List﹤T﹥)称为开放构造类型 (open constructed type)。不使用类型形参的构造类型(例如 List﹤int﹥)称为封闭构造类型 (closed constructed type)。
泛型类型可根据类型形参的数目进行“重载”;这就是说,同一命名空间或外层类型声明中的两个类型声明可以使用相同标识符,只要这两个声明具有不同数目的类型形参即可。
- class C {}
-
- class C﹤V﹥ {}
-
- struct C﹤U,V﹥ {}
-
- class C﹤A,B﹥ {}
类型名称解析、简单名称解析和成员访问、过程中使用的类型查找规则均会考虑类型形参的数目。
泛型类声明的基接口必须满足唯一性规则。
.Net泛型类之类型形参
类型形参可在类声明中提供。每个类型形参都是一个简单标识符,代表一个为创建构造类型而提供的类型实参的占位符。类型形参是将来提供的类型的形式占位符。而类型实参是在创建构造类型时替换类型形参的实际类型。
- type-parameter-list:
- ﹤ type-parameters ﹥
-
- type-parameters:
- attributesopt type-parameter
- type-parameters , attributesopt type-parameter
-
- type-parameter:
- identifier
类声明中的每个类型形参在该类的声明空间中定义一个名称。因此,它不能与另一个类型形参或该类中声明的成员具有相同的名称。类型形参不能与类型本身具有相同的名称。
类上的类型形参的作用域包括 class-base、type-parameter-constraints-clauses 和 class-body。与类的成员不同,此作用域不会扩展到派生类。在其作用域中,类型形参可用作类型。
- type:
- value-type
- reference-type
- type-parameter
由于类型形参可使用许多不同的实际类型实参进行实例化,因此类型形参具有与其他类型稍微不同的操作和限制。这包括:
·不能直接使用类型形参声明基类或接口
·类型形参上的成员查找规则取决于应用到该类型形参的约束(如果有)。
·类型形参的可用转换取决于应用到该类型形参的约束(如果有)。
·如果事先不知道由类型形参给出的类型是引用类型不能将标识null 转换为该类型。不过,可以改为使用默认值表达式。此外,具有由类型形参给出的类型的值可以使用 == 和 != 与null 进行比较,除非该类型形参具有值类型约束。
·仅当类型形参受 constructor-constraint 或值类型约束的约束时,才能将 new 表达式与类型形参联合使用。
·不能在属性中的任何位置上使用类型形参。
·不能在成员访问或类型名称中使用类型形参标识静态成员或嵌套类型。
·在不安全代码中,类型形参不能用作 unmanaged-type。
作为类型,类型形参纯粹是一个编译时构造。在运行时,每个类型形参都绑定到一个运行时类型,运行时类型是通过向泛型类型声明提供类型实参来指定的。因此,使用类型形参声明的变量的类型在运行时将是封闭构造类型。涉及类型形参的所有语句和表达式的运行时执行都使用作为该形参的类型实参提供的实际类型。
.Net泛型类之实例类型
每个类声明都有一个关联的构造类型,即实例类型 (instance type)。对于泛型类声明,实例类型是通过从该类型声明创建构造类型来构成的,所提供的每个类型实参替换对应的类型形参。由于实例类型使用类型形参,因此只能在类型形参的作用域中使用该实例类型;也就是在类声明的内部。对于在类声明中编写的代码,实例类型为 this 的类型。对于非泛型类,实例类型就是所声明的类。下面显示几个类声明以及它们的实例类型:
- class A﹤T﹥
- {
- class B {}
-
- class C﹤U﹥ {}
- }
-
- class D {}
.Net泛型类之基规范
类声明中指定的基类可以是构造类类型。基类本身不能是类型形参,但在其作用域中可以包含类型形参。
- class Extend﹤V﹥: V {}
-
-
泛型类声明不能使用 System.Attribute 作为直接或间接基类。
类声明中指定的基接口可以是构造接口类型。基接口本身不能是类型形参,但在其作用域中可以包含类型形参。下面的代码演示类实现和扩展构造类型的方法:
- class C﹤U,V﹥ {}
-
- interface I1﹤V﹥ {}
-
- class D: C﹤string,int﹥, I1﹤string﹥ {}
-
- class E﹤T﹥: C﹤int,T﹥, I1﹤T﹥ {}
泛型类声明的基接口必须满足唯一性规则。
如果类中的方法重写或实现基类或接口中的方法,则必须为特定类型提供相应的方法。下面的代码演示如何重写和实现方法。对此做了进一步的解释。
- class C﹤U,V﹥
- {
- public virtual void M1(U x, List﹤V﹥ y) {}
- }
-
- interface I1﹤V﹥
- {
- V M2(V);
- }
-
- class D: C﹤string,int﹥, I1﹤string﹥
- {
- public override void M1(string x, List﹤int﹥ y) {}
-
- public string M2(string x) {}
- }