原文请见:http://www.sz-accp.com.cn/xxyd/ShowArticle.asp?ArticleID=200
最近在研究C#2.0中的一些特性,对其中的泛型比较感兴趣,当得知JAVA5.0中也引入了泛型的概念后更是打算将泛型的概念进行学习与整理,以下内容均参考了《ASP.NET2.0开发指南》一书的有关介绍。
一、引入泛型的原因
一般情况下,在通用的数据结构中(例如 Statck、List、Dicionary等)存储的数据,要求必须具有相同的数据类型,那么唯一的方法是将所有的数据首先装箱为object类型,然后再存储。例如,下面的 Statck类,将其所有的数据存储在一个object类型数组中,该类型的两个方法Push和Pop,分别使用object来获取和返回数据。示意性代码如下所示。
public class Stack
{
object[] items;
public void Push(object item){…}
public object Pop(){…}
}
虽然使用装箱方法来统一数据类型能够解决问题,但是缺点也是显而易见的。第一是性能。根据装箱和堆栈的功能,使用Push方法能够向堆栈中压入任何类型的值。然而,在重新获取堆栈中的数据值时,必须在使用Pop方法拆箱的同时,应用显式转换得到合适的数据类型。这种装箱的拆箱操作增加了执行的负担,因为它带来了动态内存分配和运行时类型检查。第二个缺点是类型安全。因为编译器允许在任何类型和Object之间进行强制类型转换,所以将造成编译时类型安全的不足。这种缺点的产生主要是Stack类无法强制设置堆栈中数据类型。第三个缺点是影响工作效率。编写类型特定的数据结构以及冗繁的转换代码是一项乏味重复的且易于出错的任务。以上这些缺点,将导致Stack在使用过程中,发生很多意想不到的异常和错误,这的确让人头疼。为了有效解决以上问题,C#2.0引入了泛型。
二、泛型概述
泛型可应用于类、方法、结构、接口、委托等设计中,兼复用性、类型安全和高效率于一身是与之对应的非泛型所不及的。通常情况下,常见的泛弄应用于集合和方法中。下面首先以泛型在集合中的应用为例,说明泛型的基本概念、构建方式和优点等。在随后的内容中,再介绍泛型方法的应用。
泛型常见于集合应用中。在.NET2.0框架的类库中,提供了一个新的命名空间System.Collections.Generic,其中包含了一些新的基于泛型的容器类,例如,System.Collections.Generic.Stack、System.Collections.Generic.Dictionary、System.Collections.Generic.List、System.Collections.Generic.Queue等,这些类库可以在集合中实现泛型。下面以在堆栈中实现泛型为例,说明泛型的基本使用方法。
在堆栈中应用泛型,必须使用类System.Collections.Generic.Stack。该类的声明方式如下。
public class Stack<T>:IEnumerable<T>,Icollection,IEnumerable
Stack类具有典型的泛型特征,是一个带有类型参数T的泛型。类型参数T使用括号<和>来指定,扮演一个占位符的角色,直到使用时才指定一个具体的数据类型(有点类似C++中的类模板,但C++中类模板一般用于范围的扩充,而此时在集合中使用泛型则更像用于限定范围)。通过某种类型参数建立的Stack<T>的实例,可以无条件地接受这种数据类型的数据,这明显要比上一节中使用object装拆箱的方法好。
可以想像Stack类具有如下示意性处理过程。
public class Stack<T>
{
T[] items;
int count;
public void Push(T item){…}
public T pop(){…}
}
在以上代码中,T相当于堆栈的数据类型、Push方法接受的参数类型和Pop方法的返回值类型。这样就可以避免由于使用装拆箱方法导致的种种缺点,例如代码重用、性能、类型安全等。为了加深理解,下面给出一个Stack类具体的应用代码:
//实例化Stack类
System.Colloctions.Generic.Stack<string> stringStack =
new System.Colloctions.Generic.Stack<string>();
//添加数据
stringStack.Push (“硬盘”);
stringStack.Push (“声卡);
stringStack.Push (“电源”);
//转换为数组
Array stringArray;
stringArray = stringStack.ToArray();
//显示数据
foreach(string item in stringArray)
{
Console.WriteLine(item);
}
以上代码中,首先实例化了一个Stack类stringStack,并且设置其参数是string。这说明该类所实现堆栈的数据类型是string。然后,通过Stack类的Push方法压入3个字符串数据,并且用ToArray方法,将堆栈中的数据转换到一个数组stringArray中(此时,stringArray是一个字符串数组)。最后,使用Console.WriteLine方法将数组中的数据显示出来(逆序显示,这是堆栈的特性)。
另外,如果要求堆栈中存储的是int类型,那么可以使用同样的方法,只需要修改很很少的内容即可实现。代码如下所示。
//实例化Stack类
System.Colloctions.Generic.Stack<int> stringStack =
new System.Colloctions.Generic.Stack<int>();
//添加数据
stringStack.Push (1000);
stringStack.Push (2000);
stringStack.Push (3000);
//转换为数组
Array intArray;
intArray = stringStack.ToArray();
//显示数据
foreach(int item in intArray)
{
Console.WriteLine(item.ToString());
}
比较以上两组代码可以发现,泛型具有提高代码重用能力,提高类型安全和开发效率的能力。只要修改很少的代码,就可以实现对不同数据类型的处理。同时,具有编译器所支持的类型安全特性。因为一般代码不会强行对值类型进行装箱和拆箱操作,或者对引用类型进行向下强制转换,所以性能得到显著提高。当然,整个应用程序的性能可能会更高。
以上,是C#2.0中泛型的一些学习与理解,对于泛型还可以使用泛型方法,C#2.0中还有很其它的新特性,以后会继续学习与研究。




浙公网安备 33010602011771号