【转帖】为什么使用泛型
原帖:http://blog.csdn.net/jecray/archive/2007/04/13/1563978.aspx
有好久一段时间,我经常使用.net 1.1开发程序,发现.net 1.1缺少类似c++中的模板功能。这种支持类型参数的功能可以使我们设计一个有泛型的类,在运行时检测实际的类型。
这样意味着用一个泛型参数T,你可 以写一个MyList<T>类,在使用MyList<int>, MyList<string> 或 MyList<MyClass>时不需要担心在运行时进行转换或装箱操作。
.NET 2.0引入了一个新的名字空间 System.Collections.Generic,他包括了支持泛型的类,例如:List, Queue, Stack, LinkedList。利用他们可以使你的程序更加有效率。
泛型的优点
在.NET 2.0之前,泛型是通过 将特定类型和基类System.Object相互转换实现的。这种方法具有很大的局限性,比如ArrayList。ArrayList是一个非常好用 的集合类,可以随意存储任何值类型和引用。
list1.Add(3);
list1.Add(105);
//...
ArrayList list2 = new ArrayList();
list2.Add("First item.");
list2.Add("Second item");
//...
但是这种便利是以性能为代价的,任何被加到ArrayList的引用或值都被显示地转换成System.Object。如果那些项是 值类型,他们在加入时必须装箱,在取出时拆箱。类型转换,装箱,拆箱操作降低了性能,特别在需要对一个大的集合进行拆装箱时,性能的损耗是巨大的。
所以我们需要一个灵活的ArrayList同时提供更好的性能和支持多种类型。是否可以为ArrayList添加一个类型参 数呢?这正式泛型所提供的。泛型可以避免把所有项转换成Object,也可以使编辑器做类 型检查。
在Sytem.Collections.Generic中的List<T>进行相 同的操作:
list1.Add(3); //不需要装箱和类型转换
list1.Add("First item"); // 编译时错误
List<T>与ArrayList使用的不同只是 在声明和实例化时多了一个类型参数。而换来的好处是创建的List不但比ArrayList安全,而且速度要快,特别是在List中 存储值类型的时候。
泛型类
泛型类将操作封装成不针对特有的数据类型。泛型类最普遍的用法是实现linked lists, hash tables, stacks, queues, trees等,他们是以 相同的方式添加删除项而不关心项的数据类型。
{
T head;
T next;
}
这里T是一个类型参数,我们可以设置成 任何数据类型。
这个类可以这样实例化
这样就告诉编译器head和next属性是string。
泛型方法
将一个方法加上类型参数的声明就是泛型方法。
{
T temp;
temp = left;
left = right;
right = temp;
}
我们可以这样调用他
int b = 2;
Swap <int> (a, b);
你可以忽略类型参数因为编译器会自动加上,下面方法调用依旧是正确的:
设计自己的泛型类
下面的例子实现了一个泛型linked list
using System.Collections.Generic;
public class MyList<T> //type parameter T in angle brackets
{
private Node head;
// The nested class is also generic on T.
private class Node
{
private Node next;
//T as private member data type:
private T data;
//T used in non-generic constructor:
public Node(T t)
{
next = null;
data = t;
}
public Node Next
{
get { return next; }
set { next = value; }
}
//T as return type of property:
public T Data
{
get { return data; }
set { data = value; }
}
}
public MyList()
{
head = null;
}
//T as method parameter type:
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
public IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
注意上面类的声明
public class MyList<T>
T是类 型参数,在上面的代码中,Node的数据类型是T而不是int,string或其他。这样使程序员 方便地用这个类处理任何数据类型。
以下代码告诉我们如何用泛型类MyList<T>创建一个int list,只需简单的改 变类型参数,下面的代码就可以创建string list或其他自定义类型的list
{
static void Main(string[] args)
{
//int is the type argument.
MyList<int> list = new MyList<int>();
for (int x = 0; x < 10; x++)
list.AddHead(x);
foreach (int i in list)
Console.WriteLine(i);
Console.WriteLine("Done");
}
}
泛型可以使类具有重用性,类型安全和效率,泛型在集合中广泛的使用。
http://blog.csdn.net/chimomo/archive/2009/09/30/4620379.aspx
在 C#中,使用泛型会获得以下优势:
- 减少装箱和拆箱操作,提高性能
- 可以进行编译时类型检查
举 例说明:
使 用非泛型的集合类,利用 .NET Framework 基类库中的 ArrayList 集合类。ArrayList 是一个使用起来非常方便的集合类,无需进行修改即可用来存储任何引用或值类型。
- // The .NET Framework 1.1 way to create a list:
- System.Collections.ArrayList list1 = new System.Collections.ArrayList();
- list1.Add(8);
- list1.Add("It is raining heavily outside.");
但 这种方便是需要付出代价的。添加到 ArrayList 中的任何引用或值类型都将隐式地向上强制转换为 Object。 如果项是值类型,则必须在将其添加到列表中时进行装箱操作,在检索时进行取消装箱操作。强制转换以及装箱和取消装箱操作都会降低性能;尤其是在必须对大型 集合进行循环访问的情况下,装箱和取消装箱的影响将非常明显。
另 一个限制是缺少编译时类型检查;因为 ArrayList 将把所有项都强制转换为 Object, 所以在编译时无法防止客户端代码执行以下操作:
- System.Collections.ArrayList list = new System.Collections.ArrayList();
- // Add an integer to the list.
- list.Add(8);
- // Add a string to the list. This will compile, but may cause an error later.
- list.Add("It is raining heavily outside.");
- int t = 0;
- // This causes an InvalidCastException to be returned.
- foreach (int x in list)
- {
- t += x;
- }
尽 管将字符串和 int 组合在一个 ArrayList 中的做法在创建异类集合时是完全合法的,有时是有意图的,但这种做法更可能产生编程错误,并且直到运行时才能检测到此错误。
在 C# 语言的 1.0 和 1.1 版本中,只能通过编写自己的特定于类型的集合来避免 .NET Framework 基类库集合类中的通用代码的危险。当然,由于此类不可对多个数据类型重用,因此将丧失通用化的优点,并且您必须对要存储的每个类型重新编写该类。
ArrayList 和其他相似类真正需要的是:客户端代码基于每个实例指定这些类要使用的具体数据类型的方式。这样将不再需要向上强制转换为 T:System.Object, 同时,也使得编译器可以进行类型检查。换句话说,ArrayList 需要一个 type parameter。这正是泛型所能提供的。在 N:System.Collections.Generic 命名空间的泛型 List<T> 集合中,向该集合添加项的操作类似于以下形式:
- // The .NET Framework 2.0 way to create a list
- List<int> list1 = new List<int>();
- // No boxing, no casting:
- list1.Add(8);
- // Compile-time error:
- // list1.Add("It is raining heavily outside.");
对于客户端代码,与 ArrayList 相比,使用 List<T> 时添加的唯一语法是声明和实例化中的类型参数。虽然这稍微增加了些编码的复杂性,但好处是您可以创建一个比 ArrayList 更安全(由于指定了Type,所以可以进行编译时类型检查)并且速度更快(由于对于值类型无需进行装箱拆箱操作)的列表,特别适用于列表项是值类型的情 况。