选择显示字体大小

深入浅出.net泛型编程

  前言

  .net 2.0中泛型的出现是一个令人激动的特征。但是,什么是泛型?你需要它们吗?你会在自己的应用软件中使用它们?在本文中,我们将回答这些问题并细致地分析泛型的使用,能力及其局限性。

  类型安全

  .net中的许多语言如c#,c++和vb.net(选项strict为on)都是强类型语言。作为一个程序员,当你使用这些语言时,总会期望编译器进行类型安全的检查。例如,如果你把对一个book类型的引用转换成一个vehicle型的引用,编译器将告诉你这样的cast是无效的。

  然而,当谈到.net 1.0和1.1中的集合时,它们是无助于类型安全的。请考虑一个arraylist的例子,它拥有一个对象集合--这允许你把任何类型的对象放于该arraylist中。让我们看一下例1中的代码。

  例1.缺乏类型安全的arraylist

using system;
using system.collections;
namespace testapp
{
 class test
 {
  [stathread]
  static void main(string[] args)
  {
   arraylist list = new arraylist();
   list.add(3);
   list.add(4);
   //list.add(5.0);
   int total = 0;
   foreach(int val in list)
   {
    total = total + val;
   }
   console.writeline("total is {0}", total);
  }
 }
}

  本例中,我们建立了一个arraylist的实例,并把3和4添加给它。然后我循环遍历该arraylist,从中取出整型值然后把它们相加。这个程序将产生结果"total is 7"。现在,如果我注释掉下面这句:

list.add(5.0);

  程序将产生如下的运行时刻异常:

unhandled exception: system.invalidcastexception: specified cast is not valid.
attestapp.test.main(string[]args)in :\workarea\testapp\class1.cs:line 17

  哪里出错了呢?记住arraylist拥有一个集合的对象。当你把3加到arraylist上时,你已把值3装箱了。当你循环该列表时,你是把元素拆箱成int型。然而,当你添加值5.0时,你在装箱一个double型值。在第17行,那个double值被拆箱成一个int型。这就是失败的原因。

  注意:上面的实例,如果是用vb.net书写的话,是不会失败的。原因在于,vb.net不使用装箱机制,它激活一个把该double转换成整型的方法。但是,如果arraylist中的值是不能转换成整型的,vb.net代码还会失败。

  作为一个习惯于使用语言提供的类型安全的程序员,你希望这样的问题在编译期间浮出水面,而不是在运行时刻。这正是泛型产生的原因。

  3. 什么是泛型?

  泛型允许你在编译时间实现类型安全。它们允许你创建一个数据结构而不限于一特定的数据类型。然而,当使用该数据结构时,编译器保证它使用的类型与类型安全是相一致的。泛型提供了类型安全,但是没有造成任何性能损失和代码臃肿。在这方面,它们很类似于c++中的模板,不过它们在实现上是很不同的。

  4. 使用泛型集合

  .net 2.0的system.collections.generics 命名空间包含了泛型集合定义。各种不同的集合/容器类都被"参数化"了。为使用它们,只需简单地指定参数化的类型即可。请看例2:

  例2.类型安全的泛型列表

list<int> alist = new list<int>();
alist.add(3);
alist.add(4);
// alist.add(5.0);
int total = 0;
foreach(int val in alist)
{
 total = total + val;
}
console.writeline("total is {0}", total);

  在例2中,我编写了一个泛型的列表的例子,在尖括号内指定参数类型为int。该代码的执行将产生结果"total is 7"。现在,如果我去掉语句doublelist.add(5.0)的注释,我将得到一个编译错误。编译器指出它不能发送值5.0到方法add(),因为该方法仅接受int型。不同于例1,这里的代码实现了类型安全

  5. clr对于泛型的支持

  泛型不仅是一个语言级上的特征。.net clr能识别出泛型。在这种意义上说,泛型的使用是.net中最为优秀的特征之一。对每个用于泛型化的类型的参数,类也同样没有脱离开微软中间语言(msil)。换句话说,你的配件集仅包含你的参数化的数据结构或类的一个定义,而不管使用多少种不同的类型来表达该参数化的类型。例如,如果你定义一个泛型类型mylist<t>,仅仅该类型的一个定义出现在msil中。当程序执行时,不同的类被动态地创建,每个类对应该参数化类型的一种类型。如果你使用mylist<int>和mylist<double>,有两种类即被创建。当你的程序执行时,让我们进一步在例3中分析这一点。

  例3.创建一个泛型类

//mylist.cs
#region using directives
using system;
using system.collections.generic;
using system.text;
#endregion
namespace clrsupportexample
{
 public class mylist<t>
 {
  private static int objcount = 0;
  public mylist()
  {objcount++; }
  public int count
  {
   get
    {return objcount; }
  }
 }
}
//program.cs
#region using directives
using system;
using system.collections.generic;
using system.text;
#endregion
namespace clrsupportexample
{
 class sampleclass {}
 class program
 {
  static void main(string[] args)
  {
   mylist<int> myintlist = new mylist<int>();
   mylist<int> myintlist2 = new mylist<int>();
   mylist<double> mydoublelist = new mylist<double>();
   mylist<sampleclass> mysamplelist = new mylist<sampleclass>();
   console.writeline(myintlist.count);
   console.writeline(myintlist2.count);
   console.writeline(mydoublelist.count);
   console.writeline(mysamplelist.count);
   console.writeline(new mylist<sampleclass>().count);
   console.readline();
  }
 }
}

  该例中,我创建了一个称为mylist泛型类。为把它参数化,我简单地插入了一个尖括号。在<>内的t代表了实际的当使用该类时要指定的类型。在mylist类中,定义了一个静态字段objcount。我在构造器中增加它的值。因此我能发现使用我的类的用户共创建了多少个那种类型的对象。属性count返回与被调用的实例同类型的实例的数目。

  在main()方法,我创建了mylist<int>的两个实例,一个mylist<double>的实例,还有两个mylist<sampleclass>的实例--其中sampleclass是我已定义了的类。问题是:count(上面的程序的输出)的值该是多少?在你继阅读之前,试一试回答这个问题。

  解决了上面的问题?你得到下列的答案了吗?

2
2
1
1
2

  前面两个2对应mylist<int>,第一个1对应mylist<double>,第二个1对应mylist<sampleclass>--在此,仅创建一个这种类型的实例。最后一个2对应mylist<sampleclass>,因为代码中又创建了这种类型的另外一个实例。上面的例子说明mylist<int>是一个与mylist<double>不同的类,而mylist<double>又是一个与mylist<sampleclass>不同的类。因此,在这个例中,我们有四个类:mylist: mylist<t>,mylist<int>,mylist<double>和mylist<x>。注意,虽然有4个mylist类,但仅有一个被存储在msil。怎么能证明这一点?请看图1显示出的使用工具ildasm.exe生成的msil代码。


图 1.例3的msil


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范