C#高级编程:泛型优点和特性
泛型是CLR 2.0的一个新特性,在CLR 1.0中,要创建一个灵活的类或方法,但该类或方法在编译期间不知道使用什么类,就得以Object类为基础。而Object在编译期间没有类型安全性,因此必须进行强制类型转换,同时,给值类型使用Object类会有性能损失。泛型类使用泛型类型,并可以根据需要用特定的类型替换泛型类型。这就保证了类型安全性:如果某个类型不支持泛型类,编译器就会报错。
一、泛型有以下几个优点:
1)性能
对值类型使用非泛型集合类,在把值类型转换为引用类型,和把引用类型转换为值类型时,需要进行装箱和拆箱操作。装箱和拆箱的操作很容易实现,但是性能损失较大。假如使用泛型,就可以避免装箱和拆箱操作。
ArrayList list=new ArrayList();
list.Add(); //装箱,list存放的是object类型元素,须将值类型转化为引用类型
int i=(int)list[]; //拆箱,list[0]的类型是object,要赋值就得把引用类型转化为值类型
如果换成泛型编程,就不会有装箱和拆箱的性能损失。
list.Add(); //因为指定了用int来实例化,因此不必装箱
int i=list[]; //同样地,访问时也不需要拆箱
2)类型安全
与ArrayList类一样,如果使用对象,可以在这个集合中添加任意类型。
如果使用非泛型编程,如下代码,就有可能在某些情况下会发生异常。

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

如果该用泛型编程,则可以避免这种异常,让编译器检查出错误。
List<int> list=new List<int>();
list.Add();
lsit.Add("string"); //编译时报错,只能报整数类型添加到集合中
list.Add(new MyClass()); //同上
3)二进制代码重用
泛型可以定义一次,用许多不同的类型实例化,不需要像C++模板那样访问源代码。泛型可以在一种语言中定义,在另一种.NET语言中使用。
4)代码的扩展
因为泛型类的定义会放在程序集中,所以用某个类型实例化泛型泛型类不会在IL代码中复制这些类。但是,在JIT编译器把泛型类编译为内部代码时,会给每个值类型创建一个新类。引用类型共享同一个内部类的所有实现代码。这是因为引用类型在实例化的泛型类中只需要4字节的内存单元(32位系统),就可以引用一个引用类型。值类型包含在实例化的泛型类的内存中。而每个值类型对内存的要求都不同,所以要为每个值类型实例化一个新类。
二、泛型类的特性
1)默认值
在给类型T初始化时,要注意不能把null赋予泛型类型。因为泛型类型也可以实例化为值类型,而null只能用于引用类型。为了解决这个问题,可以用default关键字。通过default关键字,将null赋予引用类型,将0赋予值类型。
public T GetDoucumet()
{
T doc=default(T);
lock(this)
{
doc=documentQueue.Dequeue();
}
return doc;
}
补充:default关键字根据上下文可以有多种含义。switch语句使用default定义默认情况。在泛型中,根据泛型类型是引用类型还是值类型,default关键字用于将泛型类型初始化为null或0。
2)约束
如果泛型类需要调用泛型类型上的方法,就必须添加约束。
publicclass DocumentManager<T>
{
privatereadonly Queue<T> documentQueue=new Queue<T>(); publicvoid AddDocument(T doc)
{
lock(this)
{
documentQueue.Enqueue(doc);
}
} publicbool IsDocumentAvailable
{
get
{
return documentQueue.Count>;
}
}
} publicinterface IDocument
{
string Title{get;set;}
string Content{get;set;}
} publicclass Document:IDocument
{
public Document()
{
} public Document(string title,string content)
{
this.title=title;
this.content=content;
} publicstring Title{get;set;}
publicstring Content{get;set;}
}
如果使用DocumentManager<T>类显示文档,可以将类型T强制转换为IDocument接口
publicvoid DisplayAllDocument()
{
foreach(T doc in documentQueue)
{
Console.WriteLine(((IDocument)doc).Title);
}
}
假如类型T没有执行IDocument接口,这个类型转换就会生成一个异常,因此需给DocumentManager<T>类定义一个约束:T必须执行IDocument接口,为了在泛型类型的名称中指定该要求,将T改为TDocument。wherer子句指定了执行IDocument接口的要求。
publicclass DocumentManager<TDocument>where TDocument:IDocument
{
....
}
这样编写foreach语句就可以让类型T包含Title属性。
publicvoid DisplayAllDocument()
{
foreach(TDocument doc in documentQueue)
{
Console.WriteLine(doc.Title);
}
}
在Main()方法中,DocumentManager<T>类用Document类型来实例化,而Document类型执行了需要的IDocument接口。
staticvoid Main()
{
DocumentManager<Document> dm=new DocumentManager<Document>();
dm.AddDocument(new Document("Title A","A"));
dm.AddDocument(new Document("Title B","B"));
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接口,且必须有一个默认构造函数。
publicclass MyClass<T>where t:IFoo,new()
{
...
}
3)继承
泛型类型可以执行泛型接口,也可以派生于一个类。泛型类可以派生于泛型基类:
publicclass Base<T>
{ } publicclass Derived<T>:Base<T>
{ }
要求必须重复接口的泛型类型,或者必须指定基类的类型。
publicclass Base<T>
{ } publicclass Derived<T>:Base<string>
{ }
所以,派生类可以是泛型类或非泛型类。如可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现。
publicabstractclass Calc<T>
{
publicabstract T Add(T x,T y);
publicabstract T Sub(T x,T y);
} publicclass SimpleCalc:Calc<int>
{
publicoverrideint Add(int x,int y)
{
return x+y;
} publicoverrideint Sub(int x,int y)
{
return x-y;
}
}
4)静态成员
泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。
publicclass StaticDemo<T>
{
publicstaticint x;
}
对一个string类型和一个int类型使用了StaticDemo<T>类,所以存在两组静态字段:
StaticDemo<string>.x=;
StaticDemo<int>.x=;
Console.WrileLine(StaticDemo<string>.x); //将会输出4
C#高级编程:泛型优点和特性的更多相关文章
- 《C#高级编程(第六版)》泛型学习笔记(一):泛型优点和特性 (转载)
原文出处:http://www.cnblogs.com/xun126/archive/2011/01/13/1933838.html 泛型是CLR 2.0的一个新特性,在CLR 1.0中,要创建一个灵 ...
- C#高级编程9 第17章 使用VS2013-C#特性
C#高级编程9 第17章 使用VS2013 编辑定位到 如果默认勾选了这项,请去掉勾选,因为勾选之后解决方案的目录会根据当前文件选中. 可以设置项目并行生成数 版本控制软件设置 所有文本编辑器行号显示 ...
- C#高级编程9-第5章 泛型
泛型 1.泛型概述 泛型是C#的部分与中间语言IL集成.创建的类或方法指定了类型,在实例化和调用时必须指定类型进行操作. 泛型可以用于类.方法.接口和委托以及结构. 泛型也是结构,同时是运行库CLR定 ...
- 读《C#高级编程》第1章问题
读<C#高级编程>第1章 .Net机构体系笔记 网红的话:爸爸说我将来会是一个牛逼的程序员,因为我有一个梦,虽然脑壳笨但是做事情很能坚持. 本章主要是了解.Net的结构,都是一些概念,并没 ...
- javascript高级编程笔记01(基本概念)
1.在html中使用JavaScript 1. <script> 元素 <script>定义了下列6个属性: async:可选,异步下载外部脚本文件. charset:可选, ...
- C# 6 与 .NET Core 1.0 高级编程 - 38 章 实体框架核心(上)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 38 章 实体框架核心(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# 6 ...
- C# 6 与 .NET Core 1.0 高级编程 - 40 ASP.NET Core(上)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 40 章 ASP.NET Core(上)),不对的地方欢迎指出与交流. 章节出自<Professiona ...
- C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)),不对的地方欢迎指出与交流. 章节出自<Professional C# ...
- C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(下)
译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(下)),不对的地方欢迎指出与交流. 章节出自<Professional C# ...
随机推荐
- C# 百分比的获取
这里介绍 C# 百分比转换有2种方式 例: double a=50; double b=100; a/b.ToString("0.00%"); 或 a/b.ToString(&qu ...
- memcache 细究(一)
memcached是高性能的分布式的内存缓存服务器.由国外社区网站LIVEJOURNAL的开发团队开发. 使用目的: 通过缓存数据库查询结果,减少数据库的访问次数,以提高动态web应用的速度.提高可扩 ...
- 读Zepto源码之Deferred模块
Deferred 模块也不是必备的模块,但是 ajax 模块中,要用到 promise 风格,必需引入 Deferred 模块.Deferred 也用到了上一篇文章<读Zepto源码之Callb ...
- android-iconify 使用详解
android-iconify 使用详解 有图有真相 1.android-iconify简介 iconify的github地址:https://github.com/JoanZapata/androi ...
- HA分布式集群二hive配置
一,概念 hive:是一种数据仓库,数据储存在:hdfs上,hsql是由替换简单的map-reduce,hive通过mysql来记录映射数据 二,安装 1,mysql安装: 1,检测是否有mariad ...
- 深搜(DFS)广搜(BFS)详解
图的深搜与广搜 一.介绍: p { margin-bottom: 0.25cm; direction: ltr; line-height: 120%; text-align: justify; orp ...
- MySQL系列(五)---总结MySQL中的锁
MySQL中的锁 目录 MySQL系列(一):基础知识大总结 MySQL系列(二):MySQL事务 MySQL系列(三):索引 MySQL系列(四):引擎 概述 MyISAM支持表锁,InnoDB支持 ...
- PIVOT行转列
PIVOT通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执行聚合. 测试数据 INSERT INTO [TestRows2Columns] ...
- 七月SSL行业新闻回顾
大事件一:被泄露的私钥和基于假私钥进行的撤回 上个月,我们报告说Spotify和Cisco在应用程序中捆绑了有效证书的私钥.这些证书将根据基准要求被撤销,但应用程序不是泄露私钥的唯一来源.Koen R ...
- ps命令用法
转自:http://www.cnblogs.com/peida/archive/2012/12/19/2824418.html Linux中的ps命令是Process Status的缩写.ps命令用来 ...