泛型是CLR 2.0的一个新特性,在CLR 1.0中,要创建一个灵活的类或方法,但该类或方法在编译期间不知道使用什么类,就得以Object类为基础。而Object在编译期间没有类型安全性,因此必须进行强制类型转换,同时,给值类型使用Object类会有性能损失。泛型类使用泛型类型,并可以根据需要用特定的类型替换泛型类型。这就保证了类型安全性:如果某个类型不支持泛型类,编译器就会报错。

  一、泛型有以下几个优点:

  1)性能

  对值类型使用非泛型集合类,在把值类型转换为引用类型,和把引用类型转换为值类型时,需要进行装箱和拆箱操作。装箱和拆箱的操作很容易实现,但是性能损失较大。假如使用泛型,就可以避免装箱和拆箱操作。

  1. ArrayList list=new ArrayList();
  2. list.Add(); //装箱,list存放的是object类型元素,须将值类型转化为引用类型
  3. int i=(int)list[]; //拆箱,list[0]的类型是object,要赋值就得把引用类型转化为值类型

  如果换成泛型编程,就不会有装箱和拆箱的性能损失。

List<T> list=new List<int>();
list.Add(); //因为指定了用int来实例化,因此不必装箱
int i=list[]; //同样地,访问时也不需要拆箱

  

  2)类型安全

  与ArrayList类一样,如果使用对象,可以在这个集合中添加任意类型。

  如果使用非泛型编程,如下代码,就有可能在某些情况下会发生异常。

ArrayList list=new ArrayList();
list.Add();
list.Add("string");
list.Add(new MyClass());

foreach(int i in list)
{
Console.WriteLine(i); //这里会有个异常,因为并不是集合中的所有元素都可以转化为int
 }

  如果该用泛型编程,则可以避免这种异常,让编译器检查出错误。

  1. List<int> list=new List<int>();
  2. list.Add();
  3. lsit.Add("string"); //编译时报错,只能报整数类型添加到集合中
  4. list.Add(new MyClass()); //同上

  

  3)二进制代码重用

  泛型可以定义一次,用许多不同的类型实例化,不需要像C++模板那样访问源代码。泛型可以在一种语言中定义,在另一种.NET语言中使用。

  4)代码的扩展

  因为泛型类的定义会放在程序集中,所以用某个类型实例化泛型泛型类不会在IL代码中复制这些类。但是,在JIT编译器把泛型类编译为内部代码时,会给每个值类型创建一个新类。引用类型共享同一个内部类的所有实现代码。这是因为引用类型在实例化的泛型类中只需要4字节的内存单元(32位系统),就可以引用一个引用类型。值类型包含在实例化的泛型类的内存中。而每个值类型对内存的要求都不同,所以要为每个值类型实例化一个新类。

  二、泛型类的特性

  1)默认值

在给类型T初始化时,要注意不能把null赋予泛型类型。因为泛型类型也可以实例化为值类型,而null只能用于引用类型。为了解决这个问题,可以用default关键字。通过default关键字,将null赋予引用类型,将0赋予值类型。

  1.  
  2. public T GetDoucumet()
  3. {
  4. T doc=default(T);
  5. lock(this)
  6. {
  7. doc=documentQueue.Dequeue();
  8. }
  9. return doc;
  10. }

补充:default关键字根据上下文可以有多种含义。switch语句使用default定义默认情况。在泛型中,根据泛型类型是引用类型还是值类型,default关键字用于将泛型类型初始化为null或0。

  2)约束

  如果泛型类需要调用泛型类型上的方法,就必须添加约束。

  1.  
  2. publicclass DocumentManager<T>
  3. {
  4. privatereadonly Queue<T> documentQueue=new Queue<T>();
  5.  
  6. publicvoid AddDocument(T doc)
  7. {
  8. lock(this)
  9. {
  10. documentQueue.Enqueue(doc);
  11. }
  12. }
  13.  
  14. publicbool IsDocumentAvailable
  15. {
  16. get
  17. {
  18. return documentQueue.Count>;
  19. }
  20. }
  21. }
  22.  
  23.  publicinterface IDocument
  24. {
  25. string Title{get;set;}
  26. string Content{get;set;}
  27. }
  28.  
  29.  publicclass Document:IDocument
  30. {
  31. public Document()
  32. {
  33. }
  34.  
  35. public Document(string title,string content)
  36. {
  37. this.title=title;
  38. this.content=content;
  39. }
  40.  
  41. publicstring Title{get;set;}
  42. publicstring Content{get;set;}
  43. }

  如果使用DocumentManager<T>类显示文档,可以将类型T强制转换为IDocument接口

  1.  
  2. publicvoid DisplayAllDocument()
  3. {
  4. foreach(T doc in documentQueue)
  5. {
  6. Console.WriteLine(((IDocument)doc).Title);
  7. }
  8. }

  假如类型T没有执行IDocument接口,这个类型转换就会生成一个异常,因此需给DocumentManager<T>类定义一个约束:T必须执行IDocument接口,为了在泛型类型的名称中指定该要求,将T改为TDocument。wherer子句指定了执行IDocument接口的要求。

  1. publicclass DocumentManager<TDocument>where TDocument:IDocument
  2. {
  3. ....
  4. }

  这样编写foreach语句就可以让类型T包含Title属性。

  1.  
  2. publicvoid DisplayAllDocument()
  3. {
  4. foreach(TDocument doc in documentQueue)
  5. {
  6. Console.WriteLine(doc.Title);
  7. }
  8. }

  在Main()方法中,DocumentManager<T>类用Document类型来实例化,而Document类型执行了需要的IDocument接口。

  1. staticvoid Main()
  2. {
  3. DocumentManager<Document> dm=new DocumentManager<Document>();
  4. dm.AddDocument(new Document("Title A","A"));
  5. dm.AddDocument(new Document("Title B","B"));
  6. dm.DisplayAllDocument();

  除此之外,泛型还有几种约束类型。如下:

  1)where T:struct  使用结构约束。类型T必须是值类型

  2)where T:class  类约束指定,类型T必须是引用类型

  3)where T:IFoo  指定类型T必须执行接口IFoo

  4)where T:Foo  指定类型T必须派生于基类Foo

  5)where T:new()  构造函数约束,指定类型T必须有一个默认构造函数

  6)where T:U  类型T1派生于泛型类型T2。该约束也成为裸类型约束。

  注意:使用泛型类型还可以合并多个约束。where T:IFoo,new()约束和MyClass<T>声明指定,类型T必须执行IFoo接口,且必须有一个默认构造函数。

  1. publicclass MyClass<T>where t:IFoo,new()
  2. {
  3. ...
  4. }

  

  3)继承

   泛型类型可以执行泛型接口,也可以派生于一个类。泛型类可以派生于泛型基类:

  1.  
  2. publicclass Base<T>
  3. {
  4.  
  5. }
  6.  
  7.  publicclass Derived<T>:Base<T>
  8. {
  9.  
  10. }

  要求必须重复接口的泛型类型,或者必须指定基类的类型。

  1.  
  2. publicclass Base<T>
  3. {
  4.  
  5. }
  6.  
  7.  publicclass Derived<T>:Base<string>
  8. {
  9.  
  10. }

  所以,派生类可以是泛型类或非泛型类。如可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现。

  1.  
  2. publicabstractclass Calc<T>
  3. {
  4. publicabstract T Add(T x,T y);
  5. publicabstract T Sub(T x,T y);
  6. }
  7.  
  8.  publicclass SimpleCalc:Calc<int>
  9. {
  10. publicoverrideint Add(int x,int y)
  11. {
  12. return x+y;
  13. }
  14.  
  15. publicoverrideint Sub(int x,int y)
  16. {
  17. return x-y;
  18. }
  19. }

  4)静态成员

  泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。

  1. publicclass StaticDemo<T>
  2. {
  3. publicstaticint x;
  4. }

  对一个string类型和一个int类型使用了StaticDemo<T>类,所以存在两组静态字段:

  1. StaticDemo<string>.x=;
  2. StaticDemo<int>.x=;
  3. Console.WrileLine(StaticDemo<string>.x); //将会输出4
 
 
posted on 2011-01-13 20:38 阿寻 阅读(3719) 评论(1) 编辑 收藏

C#高级编程:泛型优点和特性的更多相关文章

  1. 《C#高级编程(第六版)》泛型学习笔记(一):泛型优点和特性 (转载)

    原文出处:http://www.cnblogs.com/xun126/archive/2011/01/13/1933838.html 泛型是CLR 2.0的一个新特性,在CLR 1.0中,要创建一个灵 ...

  2. C#高级编程9 第17章 使用VS2013-C#特性

    C#高级编程9 第17章 使用VS2013 编辑定位到 如果默认勾选了这项,请去掉勾选,因为勾选之后解决方案的目录会根据当前文件选中. 可以设置项目并行生成数 版本控制软件设置 所有文本编辑器行号显示 ...

  3. C#高级编程9-第5章 泛型

    泛型 1.泛型概述 泛型是C#的部分与中间语言IL集成.创建的类或方法指定了类型,在实例化和调用时必须指定类型进行操作. 泛型可以用于类.方法.接口和委托以及结构. 泛型也是结构,同时是运行库CLR定 ...

  4. 读《C#高级编程》第1章问题

    读<C#高级编程>第1章 .Net机构体系笔记 网红的话:爸爸说我将来会是一个牛逼的程序员,因为我有一个梦,虽然脑壳笨但是做事情很能坚持. 本章主要是了解.Net的结构,都是一些概念,并没 ...

  5. javascript高级编程笔记01(基本概念)

    1.在html中使用JavaScript 1.  <script> 元素 <script>定义了下列6个属性: async:可选,异步下载外部脚本文件. charset:可选, ...

  6. C# 6 与 .NET Core 1.0 高级编程 - 38 章 实体框架核心(上)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 38 章 实体框架核心(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# 6 ...

  7. C# 6 与 .NET Core 1.0 高级编程 - 40 ASP.NET Core(上)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 40 章  ASP.NET Core(上)),不对的地方欢迎指出与交流. 章节出自<Professiona ...

  8. C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# ...

  9. C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(下)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(下)),不对的地方欢迎指出与交流. 章节出自<Professional C# ...

随机推荐

  1. Mac之OS系统下搭建JavaEE环境 <五> 之Mysql数据库的安装及配置

    这里将推荐两款 集成的Mysql环境 十分轻便好用,MAMP 和 XAMPP MAMP XAMPP 1.MAMP下载 官网: https://www.mamp.info/en/ 下载安装即可使用 MA ...

  2. Android 动画——Frame Animation与Tween Animation

    很多手机应用的引导页都是动画的,添加动画后的应用画面会更加生动灵活,今天博主也学习了Android中Animation的使用,下面来总结下.  android中的Animation分为两种,一种是Fr ...

  3. 使用ant自动构建apk

    最近因渠道过多,需要单独接入渠道支付sdk的渠道也很多,而首发在即.人手不足,所以着手了部分相关的工作,看了下目前的操作流程..无奈人比较懒,所以决定进行一波简化的技术,先考虑到了两种方案: 1)脚本 ...

  4. Django学习(一)---基本配置及创建项目、应用

    安装:在Django官网下载最新版Django然后通过pip安装即可 一.创建项目 进入文件夹,打开cmd窗口,输入django-admin startproject myblog(项目名) 二.创建 ...

  5. Oracle系统表实用操作笔记

    1.取得指定用户的所有表名: SQL1: SELECT OWNER AS "对象所有者", OBJECT_NAME AS "表名", OBJECT_ID AS ...

  6. pgsql 递归查询 分页

    --向下查询 WITH RECURSIVE res AS ( union ALL SELECT t_tree.* FROM t_tree, res WHERE t_tree.pid = res.id ...

  7. MySQL触发器更新和插入操作

    一.触发器概念 触发器(trigger):监视某种情况,并触发某种操作,它是提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动 ...

  8. Ubuntu14.04_x64_Caffe_GPU环境配置

    为了让Caffe支持GPU模式,需要安装GPU和CUDA Toolkit,依据NVIDIA官方教程以ubuntu14.04_X64安装cuda8.0,配置Gpu为例如下所示: 1.检查安装环境,是否具 ...

  9. 登录界面Demo

    今天记载一个Demo,这个是我练习项目中用到,供新手看看,界面图:

  10. Memcached的基础梳理

    1 .Memcached 概念 官方解释如下: What is Memcached? Free & open source, high-performance, distributed mem ...