[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
[2] [你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
[3] [你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
系列文章导航:
[你必须知道的.NET] 第四回:后来居上:class和struct
[你必须知道的.NET] 第五回:深入浅出关键字---把new说透
[你必须知道的.NET] 第六回:深入浅出关键字---base和this
[你必须知道的.NET] 第七回:品味类型---从通用类型系统开始
[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
[你必须知道的.NET] 第十回:品味类型---值类型与引用类型(下)-应用征途
[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)
[你必须知道的.NET] 第十二回:参数之惑---传递的艺术(下)
[你必须知道的.NET] 第十三回:从Hello, world开始认识IL
[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在
[你必须知道的.NET] 第十六回:深入浅出关键字---using全接触
[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考
[你必须知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二
比较出真知:
• 值类型继承自ValueType(注意:而System.ValueType又继承自System.Object);而引用类型继承自System.Object。
• 值类型变量包含其实例数据,每个变量保存了其本身的数据拷贝(副本),因此在默认情况下,值类型的参数传递不会影响参数本身;而引用类型变量保存了其数据的引用地址,因此以引用方式进行参数传递时会影响到参数本身,因为两个变量会引用了内存中的同一块地址。
• 值类型有两种表示:装箱与拆箱;引用类型只有装箱一种形式。我会在下节以专门的篇幅来深入讨论这个话题。
• 典型的值类型为:struct,enum以及大量的内置值类型;而能称为类的都可以说是引用类型。 struct和class主要的区别可以参见我的拙作《第四回:后来居上:class和struct》来详细了解,也是对值类型和引用类型在应用方面的有力补充。
• 值类型的内存不由GC(垃圾回收,Gabage Collection)控制,作用域结束时,值类型会自行释放,减少了托管堆的压力,因此具有性能上的优势。例如,通常struct比class更高效;而引用类型的内存回收,由GC来完成,微软甚至建议用户最好不要自行释放内存。
• 值类型是密封的(sealed),因此值类型不能作为其他任何类型的基类,但是可以单继承或者多继承接口;而引用类型一般都有继承性。
• 值类型不具有多态性;而引用类型有多态性。
• 值类型变量不可为null值,值类型都会自行初始化为0值;而引用类型变量默认情况下,创建为null值,表示没有指向任何托管堆的引用地址。对值为null的引用类型的任何操作,都会抛出NullReferenceException异常。
• 值类型有两种状态:装箱和未装箱,运行库提供了所有值类型的已装箱形式;而引用类型通常只有一种形式:装箱。
3. 对症下药-应用场合与注意事项
现在,在内存机制了解和通用规则熟悉的基础上,我们就可以很好的总结出值类型和引用类型在系统设计时,如何作出选择?当然我们的重点是告诉你,如何去选择使用值类型,因为引用类型才是.NET的主体,不必花太多的关照就可以赢得市场。
• MSDN中建议以类型的大小作为选择值类型或者引用类型的决定性因素。数据较小的场合,最好考虑以值类型来实现可以改善系统性能;
• 结构简单,不必多态的情况下,值类型是较好的选择;
• 类型的性质不表现出行为时,不必以类来实现,那么用以存储数据为主要目的的情况下,值类型是优先的选择;
• 参数传递时,值类型默认情况下传递的是实例数据,而不是内存地址,因此数据传递情况下的选择,取决于函数内部的实现逻辑。值类型可以有高效的内存支持,并且在不暴露内部结构的情况下返回实例数据的副本,从安全性上可以考虑值类型,但是过多的值传递也会损伤性能的优化,应适当选择;
• 值类型没有继承性,如果类型的选择没有子类继承的必要,优先考虑值类型;
• 在可能会引起装箱与拆箱操作的集合或者队列中,值类型不是很好的选择,因为会引起对值类型的装箱操作,导致额外内存的分配,例如在Hashtable。关于这点我将在后续的主题中重点讨论。
3.2 引用类型的应用场合
• 可以简单的说,引用类型是.NET世界的全值杀手,我们可以说.NET世界就是由类构成的,类是面向对象的基本概念,也是程序框架的基本要素,因此灵活的数据封装特性使得引用类型成为主流;
• 引用类型适用于结构复杂,有继承、有多态,突出行为的场合;
• 参数传递情况也是考虑的必要因素;