yanzimywife

专注于技术

   :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

学过c++的朋友一定对下面的代码很熟悉吧:

 1#include<iostream>
 2using namespace std;
 3template<class T> class array
 4{
 5  public:
 6     array(int size)
 7      {
 8        a=new t[size];
 9      }
10  //more interface.
11  private:
12     T* a;
13}
园子里的很多朋友都是从c++的template开始学习泛型编程的吧.
以前一直以为c#没有泛性编程这个东西(惭愧啊),这几天才了解到其实c#2.0已经加入了这个激动人心的功能.
晚是晚了点,但是这么好的东西还是必须学习的.


一.什么是泛形
 微软给出的定义是:"泛型可以让类、结构、接口、委托和方法按它们存储和操作的数据的类型进行参数化"
我对这句话的理解为:
 我们可以让类、结构、接口、委托和方法的字段,参数或者局部变量的类型动态的定义,而不需要为每种类型都进行定义.
二.为什么使用泛型
正如前面所说的我们不必因为类、结构、接口、委托和方法的字段,参数或者局部变量的类型不同,而定义不同的版本.
如果没有泛型的话我没定义Stack类则必须这样定义:
public class Stack
{
    
int[] items;
    
int count;
    
public void Push(int item) {}
    
public int Pop() {}
}

这样我们就定义了一个int型的堆栈,这样看起来还不错,但是如果现在我们不仅需要一个int堆栈还要一个string类型的堆栈呢,这同样很简单我只要再定义一个string类型的堆栈
public class Stack
{
    
string[] items;
    
int count;
    
public void Push(string item) {}
    
public string Pop() {}
}

这样看起来也还不错,还是能很好的完成我们的工作,但是如果我们还要double,byte,Employee.....等等类型的堆栈呢,难道我们都要一个个去定义吗??

我相信聪明的大家肯定不会这样做的,大家都知道.NET有个特殊的 object类,讲到这里我想大家已经猜到了我要干什么了吧。对,我要用Object对象来实现这个堆栈.

 1public class Stack
 2{
 3   object[] items;
 4int count;
 5
 6public void Push(object item) {}
 7
 8public object Pop() {}
 9}

10
这样总没有什么问题了吧,我只要定义一个Stack类,什么类型都能用了.
问题没有这么简单吧,大家先看下面的代码
//性能问题
Stack stack = new Stack();
stack.Push(
3);
int i = (int)stack.Pop();
//安全问题
Stack stack = new Stack();
stack.Push(
new Customer());
string s = (string)stack.Pop();


当我们i传递给 Push 方法时则该值将自动被装箱。当以后检索该 int 时,必须使用显式类型强制转换将其取消装箱.这样的装箱和取消装箱操作由于涉及动态内存分配和运行时类型检查而额外增加了性能开销.

同时,虽然上面的代码错误使用了 Stack 但是从技术角度讲该代码可以视作是正确的编译器不会报告编译时错误。这个问题在该代码被执行之前不会暴露出来,但在执行该代码时会引发 InvalidCastException

显然如果能够指定元素类型Stack 类将能够从中受益。
三.创建泛型

泛型提供了一种新的创建类型的机制使用泛型创建的类型将带有类型形参。下面的示例声明一个带有类型形参 T 的泛型 Stack 类。类型形参在 < > 分隔符中指定并放置在类名后。Stack<T> 的实例的类型由创建时所指定的类型确定,该实例将存储该类型的数据而不进行数据类型转换。这有别于同 object 之间的相互转换。类型形参 T 只起占位符的作用,直到在使用时为其指定了实际类型。注意,这里的 T 用作内部项数组的元素类型、传递给 Push 方法的参数类型和 Pop 方法的返回类型:

 1public class Stack<T>
 2{
 3T[] items;
 4int count;
 5
 6public void Push(T item) {}
 7
 8public T Pop() {}
 9}

10

简单把:)
四.使用泛型
泛型的堆栈我们是定义好了,那么我们该怎么用他呢??定义都这么简单用起来肯定也不会难的
1Stack<int> stack = new Stack<int>();
2stack.Push(3);
3int x = stack.Pop();

Stack<int> 类型中出现的每个 T 都被替换为类型实参 int。在创建 Stack<int> 的实例后items 数组的本机存储是 int[] 而不是 object[]。无疑,这比非泛型的 Stack提供了更高的存储效率。同样,Stack<int> Push Pop 方法所操作的也是 int 类型的值。如果将其他类型的值推入堆栈则产生编译时错误。而且在检索值时也不再需要将它们显式强制转换为原始类型。

同时泛型提供了强类型机制,意味着如果将一个 int 值推入 Customer 对象的堆栈将导致错误.
这样就定义好了一个int 型的Stack实例.
posted on 2007-03-20 14:48  yanzimywife  阅读(1747)  评论(4编辑  收藏  举报