内容摘要 -
泛型可以让类、结构、接口、委托和方法按它们存储和操作的数据的类型进行参数化。使用过 Eiffel 或
Ada 泛型的用户或 C++ 模板的用户很快就能熟悉 C# 泛型,而且这些用户会发现 C# 泛型较之过去这些
语言更加简便易用。
19.1.1 为什么要使用泛型?
如果没有泛型,通用数据结构可通过使用类型 object 实现任何数据类型的存储。例如,下面是一个简
单的 Stack 类,它将数据存储在一个 object 数组中,它的两个方法 Push 和 Pop 分别使用 object 接
受和返回数据:
全文 -
C# 2.0语言规范讲义 - 泛型
19.1 泛型
泛型可以让类、结构、接口、委托和方法按它们存储和操作的数据的类型进行参数化。使用过 Eiffel 或
Ada 泛型的用户或 C++ 模板的用户很快就能熟悉 C# 泛型,而且这些用户会发现 C# 泛型较之过去这些
语言更加简便易用。
19.1.1 为什么要使用泛型?
如果没有泛型,通用数据结构可通过使用类型 object 实现任何数据类型的存储。例如,下面是一个简
单的 Stack 类,它将数据存储在一个 object 数组中,它的两个方法 Push 和 Pop 分别使用 object 接
受和返回数据:
public class Stack
{
object[] items;
int count;
public void Push(object item) {...}
public object Pop() {...}
}
虽然使用类型 object 使得 Stack 类非常灵活,但这种方式仍存在某些缺陷。例如,我们可以将任何类
型的值(例如一个 Customer 实例)推入堆栈。但是,当从堆栈中检索某个值时,必须将 Pop 方法的结
果显式强制转换回相应的类型,这样的代码编写起来颇为繁琐,而且在运行时执行的类型检查会造成额
外的开销从而影响性能:
Stack stack = new Stack();
stack.Push(new Customer());
Customer c = (Customer)stack.Pop();
再比如,当我们将一个值类型(例如 int)的值传递给 Push 方法时,则该值将自动被装箱。当以后检
索该 int 时,必须使用显式类型强制转换将其取消装箱:
Stack stack = new Stack();
stack.Push(3);
int i = (int)stack.Pop();
这样的装箱和取消装箱操作由于涉及动态内存分配和运行时类型检查而额外增加了性能开销。
上述 Stack 类还有一个潜在的问题就是我们无法对放到堆栈上的数据的种类施加限制。实际上,可能
会发生这种情况:将一个 Customer 实例推入堆栈,而在检索到该实例之后却意外地将它强制转换为错
误的类型:
Stack stack = new Stack();
stack.Push(new Customer());
string s = (string)stack.Pop();
虽然上面的代码错误使用了 Stack 类,但是从技术角度讲该代码可以视作是正确的,编译器不会报告
编译时错误。这个问题在该代码被执行之前不会暴露出来,但在执行该代码时会引发
InvalidCastException。
显然,如果能够指定元素类型,Stack 类将能够从中受益。有了泛型,我们便可以做到这一点。
19.1.2 创建和使用泛型
泛型提供了一种新的创建类型的机制,使用泛型创建的类型将带有类型形参 (type parameter)。下面的示
例声明一个带有类型形参 T 的泛型 Stack 类。类型形参在 < 和 > 分隔符中指定并放置在类名后。
Stack<T> 的实例的类型由创建时所指定的类型确定,该实例将存储该类型的数据而不进行数据类型转
换。这有别于同 object 之间的相互转换。类型形参 T 只起占位符的作用,直到在使用时为其指定了实
际类型。注意,这里的 T 用作内部项数组的元素类型、传递给 Push 方法的参数类型和 Pop 方法的返回
类型:
public class Stack<T>
{
T[] items;
int count;
public void Push(T item) {...}
public T Pop() {...}
}
在使用泛型类 Stack<T> 时,将指定用于替换 T 的实际类型。在下面的示例中,指定了 int 作为 T 的类
型实参 (type argument):
Stack<int> stack = new Stack<int>();
stack.Push(3);
int x = stack.Pop();
Stack<int> 类型称为构造类型 (constructed type)。在 Stack<int> 类型中,出现的每个 T 都被替换为
类型实参 int。在创建 Stack<int> 的实例后,items 数组的本机存储是 int[] 而不是 object[]。无
疑,这比非泛型的 Stack 提供了更高
|