C# 泛型 ( 一)
时间:2010-09-17 来源:czyhsl
一、泛型引入和介绍
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但是没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。有没有一种方法,在方法中传入通用的数据类型?显然是肯定有,那就是本篇文章要介绍的泛型。
为什么要使用泛型呢?一个事物的出现必然是合理的。事出有因,带着这点让我去寻找为什么泛型会出现。在网上也是看到别人的文章,感觉其中很有启发性,方便了我进入泛型的世界。
代码public class Stack
{
private int[] m_item;
public int Pop(){...}
public void Push(int item){...}
public Stack(int i)
{
this.m_item = new int[i];
}
}
上面的代码用来存储int类型应该没问题,但是我们需要栈来保存string类型时,那该怎么办呢?我们可以把这段代码复制一份,这样做肯定没问题。可以我现在还想保存long、float类型呀!这样无休止的去复制代码,岂不是降低了代码的质量。想呀想,不是有一个object吗?对,它是所有类的基类,用object代替int。
代码public class Stack现在可是object了吧!我们就可以传入任何数据类型啦!一般人可能会想问题这样就解决了。那泛型还出现干嘛呢?认真的分析上面的代码可以发现:在处理值类型时,会出现装箱、拆箱操作,这将在托管堆上分配和回收大量的变量,若数据量大,则性能损失非常严重;在处理引用类型时,虽然没有装箱和拆箱操作,但将用到数据类型的强制转换操作,增加处理器的负担。泛型恰好可以解决以上问题。 代码
{
private object[] m_item;
public object Pop(){...}
public void Push(object item){...}
public Stack(int i)
{
this.m_item = new[i];
}
}
public class Stack<T>泛型引用了通用数据类型T就可以适用任何数据类型,并且类型是安全的。实例化了int类型的栈,就不能处理string类型的数据。无需装箱和拆箱,这个类在实例化时,按照所传入的数据类型生成本地代码,本地代码数据类型已经确定。
{
private T[] m_item;
public T Pop(){...}
public void Push(T item){...}
public Stack(int i)
{
this.m_item = new T[i];
}
}
现在对泛型的优点有了一个大概的认识,接着我们就要知道如何去用它。
代码public class GenericList<T>这是MSDN上的泛型的一个小示例,对我有莫大的帮助。
{
private class Node
{
public Node(T t)
{
next = null;
data = t;
}
private Node next;
public Node Next
{
get { return next; }
set { next = value; }
}
private T data;
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node head;
public GenericList()
{
head = null;
}
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;
}
}
}
class TestGenericList
{
static void Main()
{
GenericList<int> list = new GenericList<int>();
for (int x = 0; x < 10; x++)
{
list.AddHead(x);
}
foreach (int i in list)
{
Console.Write(i + " ");
}
Console.WriteLine("\nDone");
}
}
二、泛型类
泛型类不是特定于具体数据类型的操作。它常用于集合,如链接列表、哈希表、堆栈、队列,像从集合中添加和移项这样的操作都以大体上相同的方式执行,与所存储的数据类型无关。
泛型类继承
它可以从具体的、封闭式构造或开放式构造基类继承;
class BaseNode { }
class BaseNodeGeneric<T> { }
class NodeConcrete<T> : BaseNode { }
class NodeClosed<T> : BaseNodeGeneric<int> { }
class NodeOpen<T> : BaseNodeGeneric<T> { }
具体类可以从封闭式构造基类继承,但无法从开放式构造类或裸类型参数继承;
class Node1 : BaseNodeGeneric<int> { }
//Generates an error
//class Node2 : BaseNodeGeneric<T> {}
//Generates an error
//class Node3 : T {}
从开放式构造类型继承的泛型类必须指定约束,这些约束是基类约束的超集或暗示基类型约束;
class NodeItem<T> where T : IComparable<T>, new() { }
class SpecialNodeItem<T> : NodeItem<T> where T : IComparable<T>, new() { }
泛型类型可以使用多个参数类型和约束
class SuperKeyType<K, V, U>
where U : System.IComparable<U>
where V : new()
{ }
开放式构造类型和封闭式构造类型可以用作方法参数
void Swap<T>(List<T> list1, List<T> list2)
{
}
void Swap(List<int> list1, List<int> list2)
{
}
到这里,我对泛型类的由来、语法有了一定的了解。刚开始还是很迷糊,没接触的事物总是感觉很怪异,不过我坚信只要勇于去学,总会有收获的。