C#学习笔记---C#2.0范型
虽然机子上没有C#2.0和C#3.0的编译环境,但是还是忍不住要学一下这些新东东,谁让Anders是俺偶像那.
范型允许类,结构,接口,委托和方法根据他们存储和操作的数据类型来实现参数化.C#的范型对于Eiffel和Ada范型的使用者和C++模板的使用者来说是非常熟悉的,但是他们不用承受后者(C++的模板)的复杂.
1.为什么要用范型?
如果没有范型,多用途的数据结构可以用object存储任意类型的数据.比如下面的stack类中用ojbect数组来存储数据,push和pop方法分别用objec接收和返回数据.
public class Stack
{
object[] items;
int count;
public void Push(object item) {}
public object Pop() {}
}
尽管用ojbect有很大的灵活性,但也不是没有弊端的.弊端如下:{
object[] items;
int count;
public void Push(object item) {}
public object Pop() {}
}
1.可以把任意类型的数据,如customer的实例压入栈中,但是当用pop方法返回数据的时候,必须显式地转化为适当的类型,这样不仅写代码枯燥而乏味而且增加了运行时类型检查的开销.
2.如果一个值类型的数据被压入栈,它会自动被装箱,当出栈时又要被自动拆箱.拆箱和装箱操作意味着效率的损失,因为要动态分配内存和运行时类型检查.
3.如果出栈的时候数据没有被转化为正确的类型,比如从customer转化为string,这并不会有编译时错误,但当运行的时候将会引发InvalidCastException 异常.
很明显,如果statck能够指定数据的类型,将会是一件比较惬意的事情,范型使这一切成为可能.
2.如何创建和使用范型?
先看下面的例子
public class Stack<T>
{
T[] items;
int count;
public void Push(T item) {}
public T Pop() {}
}
范型通过类型参数(type parameters)来实现创建类型方便.类型参数用<和>来指定.类型参数做为占位符(placeholders)使用知道指定真正使用的类型.T在这里用做类成员items的类型,push方法的参数类型和pop方法的返回参数类型使用.{
T[] items;
int count;
public void Push(T item) {}
public T Pop() {}
}
当Stack<T>被使用时,真实的类型将会替换T.比如下面的例子中int将会做为类型参数(type argument)替代T
Stack<int> stack = new Stack<int>();
stack.Push(3);
int x = stack.Pop();
Stack<int>类型被称作构造类型(Constructed Type),在该类型中所有的T都被类型参数int替换.当Stack<int>类型的实例被创建的时候itmes将会是int类型的,而不是object,提高了存储效率.同样push和pop方法也只能操作int类型,当把一个不是int类型的数据入栈时将会引发编译时错误,当数据出栈时也不用显式转换.stack.Push(3);
int x = stack.Pop();
范型类型可以有任意数目的类型参数.前面的stack<T>只有一个参数,但Dictionary 就可以有两个类型参数,一个做为key的类型,一个做为value的类型.
public class Dictionary<K,V>
{
public void Add(K key, V value) {}
public V this[K key] {}
}
当Dictionary<K,V>被使用的时候,必须提供两个类型参数.{
public void Add(K key, V value) {}
public V this[K key] {}
}
Dictionary<string,Customer> dict = new Dictionary<string,Customer>();
dict.Add("Peter", new Customer());
Customer c = dict["Peter"];
dict.Add("Peter", new Customer());
Customer c = dict["Peter"];