17.2 泛型类型

在方案三中使用了本章要介绍的泛型类型,它可以十分优雅地解决上述方案所遇到的这类问题。泛型类型较普通类型多了一个类型参数,例如:<T>。其中T是一个通用的类型占位符,实际上除了字母T,类型参数也可以根据需要使用其他的标识符(例如V、U、TPerson、Person、User等)。

如下是非泛型类型和泛型类型的示例:


class C{}//非泛型类

class C<V>{}//泛型类,具有一个泛型参数V

struct C<U,V>{}//泛型结构,具有两个泛型参数U和V


泛型类型的类型参数,将在实例化时根据T的实际类型,CLR会自动编译为本地代码,运行效率和代码质量都有一定提高,并且保证了数据的类型安全。下面使用泛型来改写代码清单17-1,也就是方案三的内容,如代码清单17-3所示。

代码清单17-3 使用泛型重写栈的例子


1 class Stack<T>

2{

3 private int_size;

4 private int_pointer;

5 private T[]_db;

6

7 public Stack(int size)

8{

9_size=size;

10_db=new T[_size];

11}

12

13 public void Push(T data)

14{

15 int tmp=_pointer++;

16 if(tmp<_size)

17{

18_db[tmp]=data;

19}

20}

21

22 public T Pop()

23{

24 return_db[—_pointer];

25}

26}


相比非泛型Stack类版本,上述代码有如下几点不同:

❑类的声明部分变成了Stack<T>;

❑_db数组成了T[]类型;

❑Push方法的参数成了T类型;

❑Pop方法的返回类型成了T类型。

图17-2说明了泛型类型相对于非泛型类型带来的灵活性增加,原来需要针对每种类型都有一个专门的类,现在只需要一个泛型类型就足够,代码也得到了更大程度的复用。

17.2 泛型类型 - 图1

图 17-2 泛型类型相较于非泛型类型更大程度复用了代码

可见,使用泛型是将类的共同行为提取出来,而将变化的部分抽象为类型参数。换句话说,泛型特别适用于使用同一段代码处理不同的数据类型的场景。

在C#中,除了可以创建泛型类以外,还可以创建自己的泛型接口、泛型结构、泛型方法、泛型事件和泛型委托,其中除了方法是成员以外,其余均为类。