泛型简介
泛型是C#2.0最为强大的特点之一。泛型使得我们定义类型安全(type-safe)的数据结构。因为我们可以重用数据处理的算法而无需关注数据的特定类型,从而提高开发效率和代码质量。从观念上讲,泛型类似欲C++中的模板,但是他们的实现和功能却有着很大的不同。
泛型问题描述
假设一种常用的数据结构,例如stack,他提供的经典method比如push和pop。 当我们想要开发一个通用stack(genaral-purpose)的时候,我们会想利用这种stack能够处store任意类型的实例。在C#1.1中,我们只能用一个基于对象的(object-based) stack, 也就是在stack中的内部数据结构是不定型的(amorphous),然后stack 的method与objects进行交互。
比如
Public stack stack
{
obejct[] m_Items;
public void push(object item)
{...}
public object opo()
{...}
}
Stack mystack=new Stack();
mystack.push(1);
mystack.push(2);
int number=(int)stack.pop();
第一个问题是性能performance. 当我们利用值类型的时候,我们必须采用装箱操作(box) 将他们Push到stack中,当从stack中pop时,我们必须执行unbox操作,从而导致一些不必要的垃圾回收操作。即使我们用引用类型(reference type)而不是值类型,仍然会存在性能下降,因为其必须将其从一个对象转变成(cast)与其实际交互的类型,从而增加开销。
Stack mystack=new Stack();
mystack.push("1");
string number=(string)stack.pop();
第二个问题是关于类型安全(type safety).因为编译器允许我们将任何类型转换成object或者将object转换cast)成任何类型。这样,我们便失去了编译时(compile-time)类型安全。例如,以下代码编译时没问题,但是执行时会抛出异常
stack mystack=new stack();
mystack.push(1);
string number=(string)stack.pop();
解决这个问题的方法是我们设计一种指定特定类型的stack.例如IntStack,StringStack等等。这样就失去了reuse的意义。
什么是泛型(Generics)
泛型允许我们定义一种类型安全的类,同时兼顾类型安全,性能和效率。我们只需要实现一次泛型服务,然后你就可以利用任何类型来使用它。语法为 <and > 标记,来包装一个泛型类型参数。例如,下面的代码demonstrate如何定义和使用一个泛型stack
block 1: the implementation of generic stack
public class stack<T>
{
readonly int m_size;
int m_stackpointer=0;
T[] m_Items;
public stack(int size)
{
m_size=size;
m_Items=new T[m_size];
}
public void Push(T item)
{
if(m_stackpointer>=m_size)
throw new StackOverflowException();
m_Items[m_stackpointer]=item;
m_stackpointer++;
}
public T pop()
{
m_stackpointer--;
if(m_stackpointer>=0)
return m_Items[m_stackpointer];
else
{
m_stackpointer=0;
throw new InvalidOperationException("cannot pop an empty stack");
}
}
}
blcok 2: the use of specific-type stack
public class program
{
public static void Man()
{
stack<int> mystack=new stack<int>();
mystack.push(1);
mystack.push(2);
int numnber=mystack.pop();
}
}
泛型的益处
.Net中的泛型允许我们重用代码,提高开发效率。即使改变数据类型或者内部数据,代码也不需要重写,不管是值类型或者是引用类型。我们只需要开发,测试,发布我们的代码一次后,我们就可以对任何的数据类型进行重用,包括未来未知的数据类型,所有编译器支持的和类型安全的即可。因为泛型代码不会强制执行装箱和拆箱操作,或者类型转换,因此performance得以提高。
泛型的应用
sample 1:单泛型
public struct Point<T>
{
public T X;
public T Y;
}
然后我们可以利用这个泛型点作为整数坐标点,例如
Point<int> point;
point.X=1;
point.Y=2;
多泛型
例如,以下是一个泛型的链表的示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericTest
{
public class Node<K, I>
{
public K m_key;
public I m_item;
public Node<K,I> next;
public Node()
{
}
public Node(K key, I item)
{
m_item = item;
m_key = key;
next = null;
}
}
public class List<K,I>
{
Node<K, I> m_listHead;
Node<K, I> m_listTail;
public List()
{
m_listHead = m_listTail = null;
}
public void InsertList(K key,I item)
{
Node<K, I> newNode = new Node<K, I>(key, item);
if (m_listHead == null)
m_listHead = newNode;
else
m_listTail.next= newNode;
m_listTail = newNode;
m_listTail.next = null;
}
public void ShowList()
{
Node<K,I> p;
p=m_listHead;
while (p!=null)
{
Console.WriteLine("key:{0} item:{1}", p.m_key, p.m_item);
p = p.next;
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("\nGeneric List 1 test:");
List<int, string> mylist = new List<int, string>();
mylist.InsertList(1, "herengang");
mylist.InsertList(2, "guliqun");
mylist.InsertList(4, "Herenchao");
mylist.ShowList();
List<DateTime, string> haha = new List<DateTime, string>();
Console.WriteLine("\nGeneric List 2 test:");
haha.InsertList(DateTime.Now, "AAA");
haha.InsertList(DateTime.Today, "BBB");
haha.ShowList();
}
}
}
using List = LinkedList<int,string>;
class ListClient
{
static void Main(string[] args)
{
List list = new List();
list.AddHead(123,"AAA");
}
}
说明:该文章翻译自http://msdn2.microsoft.com/en-us/library/ms379564(VS.80).aspx