为了便于文章的开展,首先介绍装箱(Boxing)和拆箱(Unboxing)这两个名词。.Net的类型分为两种,一种是值类型,另一种是引用类型。这两个类型的本质区别,值类型数据是分配在栈中,而引用类型数据分配在堆上。那么如果要把一个值类型数据放到堆上,就需要装箱操作;反之,把一个放在堆上的值类型数据取出来,则需要进行拆箱操作。

例如,对于如下简单的装箱和拆箱操作语句。

int i = 123;

object obj = i;//Boxing

if( obj is int )

int  j = (int) obj;//Unboxing

为了,更好的诠释装箱和拆箱操作,我借用MSDN关于“Boxing”的解释图,具体如下。

明白了这两名词的意思,现在说说为什么要减少装箱和拆箱操作。

原因有两个,主要是关于效率:一个就是对于堆的操作效率比较低;另一个就是对于堆上分配的内存资源,需要GC来回收,从而降低程序效率。

考虑到这两点因素,那么需要在程序中减少装箱和拆箱操作。

如何减少呢,涉及到这两个操作比较多的是,格式化输出操作,例如:String.Format,Console.WriteLine之类的语句。

例如:

Console.WriteLine( "Number list:{0}, {1}, {2}",

1,2,3 );

对于“1,2,3”来说,相当于前面的“123”一样,需要经过装箱和拆箱两个操作。那么如何避免呢,其实只要向WriteLine传递引用类型数据即可,也就是按照如下的方式。

Console.WriteLine( "Number list:{0}, {1}, {2}",

1.ToString(),2.ToString(),3.ToString() );

由于“1.ToString()”的结果是String类型,属于引用类型,因此不牵扯装箱和拆箱操作。

其次,牵扯到装箱和拆箱操作比较多的就是在集合中,例如:ArrayList或者HashTable之类。

把值类型数据放到集合中,可能会出现潜在错误。例如:

public struct Person

{

private string _Name;

public string Name

{

get{ return _Name; }

set{ _Name = value; }

}

public Person( string PersonName )

{

_Name = PersonName;

}

public override string ToString()

{

return _Name;

}

}

// Using the person in a collection

ArrayList arrPersons = new ArrayList();

Person p = new Person( "OldName" );

arrPersons.Add( p );

// Try to change the name

p = ( Person ) arrPersons[0] ;

p.Name = "NewName";

Debug.WriteLine( ( (Person ) arrPersons[0] ).Name );//It's "OldName"

这个问题其实在前面的文章中已经讲过了。有人可能会说,是否可以按照如下的方式去修改呢。

( (Person ) arrPersons[0] ).Name = "NewName";//Can't be compiled

很不幸,如上操作不能通过编译。为什么呢,对于“( (Person ) arrPersons[0] )”来说,是系统用一个临时变量来接收拆箱后的值类型数据,那么由于值类型是分配在栈上,那么操作是对实体操作,可是系统不允许对一个临时值类型数据进行修改操作。

// Using the person in a collection

ArrayList arrPersons = new ArrayList();

Person p = new Person( "OldName" );

arrPersons.Add( p );

// Try to change the name

p = ( Person ) arrPersons[0] ;

p.Name = "NewName";

arrPersons.RemoveAt( 0 );//Remove old data first

arrPersons.Insert( 0, p );//Add new data

Debug.WriteLine( ( (Person ) arrPersons[0] ).Name );//It's "NewName"

其实,这样操作会产生过多装箱和拆箱操作。那么更好的方法,可以通过接口来完成,从而减少装箱和拆箱操作。对于这个例子的接口实现应该如下。

public interface IPersonName

{

string Name{ get;set;}

}

public struct Person:IPersonName

{

private string _Name;

public string Name

{

get{ return _Name; }

set{ _Name = value; }

}

public Person( string PersonName )

{

_Name = PersonName;

}

public override string ToString()

{

return _Name;

}

}

// Using the person in a collection

ArrayList arrPersons = new ArrayList();

Person p = new Person( "OldName" );

arrPersons.Add( p );

// Change the name

( (IPersonName)arrPersons[0] ).Name = "NewName";

Debug.WriteLine( ( (Person ) arrPersons[0] ).Name );//It's "NewName"

很多人就问,为什么值类型不能修改,即

( (Person ) arrPersons[0] ).Name = "NewName";//Can't be compiled

而如上的接口类型就能修改呢,即

( (IPersonName)arrPersons[0] ).Name = "NewName";

这是由于产生的临时变量的类型不同,前者已经在前面进行说明了,后者由于产生的临时变量的类型为IPersonName,属于引用类型,那么相当于临时变量就是原对象的引用,那么对于对于它的修改会直接修改到原对象,因此是可以的。可以说这里的不同本身在于产生临时对象的类型不同,从而造成本质的区别。

通过接口来改写,这样就减少了装箱和拆箱操作,同时也保证了修改的正确性。不过要注意的是,这里接口对于的是引用类型,如果接口访问的或者返回的是值类型,那么用接口虽说能实现了,但是对于装箱和拆箱操作来说,并没有减少。

对于装箱和拆箱操作来说,基本上就讲完了,只要记住频繁装箱和拆箱操作会降低程序效率,因此在编写的时候要尽量避免。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Knight94/archive/2006/10/08/1326326.aspx

转载于:https://www.cnblogs.com/Sue_/articles/1656778.html

《Effective C#》Item 17:减少装箱(Boxing)和拆箱(Unboxing)操作相关推荐

  1. 什么是装箱(boxing)和拆箱(unboxing)?

    将值类型转换为引用类型的过程称为装箱    反之称为拆箱

  2. Java 进阶——自动装箱和自动拆箱

    1.什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供的功能. 一般我们要创建一个类的对象实例的时候,我们会这样: Class a ...

  3. 装箱和拆箱,自动装箱和自动拆箱

    装箱和拆箱,自动装箱和自动拆箱 以Integer的创建为例. 装箱和拆箱 装箱:把基本数据类型转换成包装类对象(int->Integer) Integer num1=new Integer(17 ...

  4. java-自动装箱和自动拆箱

    一.简述   自动装箱和自动拆箱是两个相反的过程,自动装箱即将基本数据类型转换为对应的封装类,自动拆箱即将封装类转换为对应的基本数据类型.此外,装箱的过程会增加内存的消耗,影响性能,因为这个过程会创建 ...

  5. 关于Integer的自动装箱与自动拆箱

    关于Integer的自动装箱与自动拆箱 自动装箱 Integer x1 = 36和Integer n1 = new Integer(36)有什么区别?我们尝试运行下面代码看看会是什么结果: publi ...

  6. java 自动装箱自动拆箱_自动装箱和自动拆箱

    自动装箱和自动拆箱 Java 提供了 8 种基本数据类型,每种数据类型都有其对应的包装类型,包装类是面向对象的类,是一种高级的数据类型,可以进行一些比较复杂的操作,它们是引用类型而不再基本类型了. 基 ...

  7. 自动装箱与自动拆箱的一些问题

    今天打算复习一下Java基础,之前学的太快速了,现在暑假,好好把那些细节看一下 复习到自动装箱和自动拆箱的时候,这里有个很有趣的现象 Integer n1 = 100; Integer n2 = 10 ...

  8. 第三次学JAVA再学不好就吃翔(part64)--自动装箱和自动拆箱

    学习笔记,仅供参考 自动装箱和自动拆箱 装箱:把基本类型转换为包装类类型 int x = 100; Integer i1 = new Integer(x); 拆箱:把包装类类型转换为基本类型 int ...

  9. java 自动装箱自动拆箱,java自动装箱、自动拆箱和正常情况性能比较

    自动装箱和自动拆箱是java5.0版本引入的,能自动将基本类型转换为对应的基本类型包装对象,那么我们比较一下他们的性能情况. package com.wmmad.test; import junit. ...

  10. 包装类,包装类的自动装箱和自动拆箱

    目标 1)包装类的作用, 2)掌握包装类的自动装箱和自动拆箱操作. 3)掌握包装类的转换操作. 具体内容 一切皆对象,八种基本数据类型不是对象. 把Int包装成一个类,这样的一个类就可以以对象的形式操 ...

最新文章

  1. DGA域名——可以每天只生成一个域名,因此最多存在365个 DGA域名;
  2. SynchronizedMap和ConcurrentHashMap的深入分析
  3. 用二叉树来理解树状数组
  4. 02 | 服务治理:Nacos 如何实现微服务服务治理
  5. 看到腾讯反驳360的文章,笑死我了。
  6. 用java编写圆锥_求java大神帮忙 求大神帮助!Java
  7. STC15学习笔记 第一章 流水灯与数码管
  8. openwrt刷回原厂固件_小米路由3刷机与刷回
  9. Bootstrap之折叠(Collapse)
  10. 【Java学习】Clone 分析
  11. java中复数的类型_java构造一个复数类
  12. 《如何让你爱的人爱上你》第三部分:自尊
  13. Gluster管理命令的总结与归纳
  14. SAS硬盘和SATA硬盘傻傻分不清?不懂的看这里
  15. DBCA创建数据库实例
  16. Web前端知识CSS(响应式设计)
  17. Python爬取食品商务网蔬菜价格数据,看看蔬菜最近的价格情况
  18. 最好的C#教程和参考书
  19. 中子测井之热中子、超热中子和补偿中子测井基本原理
  20. 目前全球和中国的区块链专利申请状况和布局状况如何?

热门文章

  1. Eugeny and Array(水题,注意题目描述即可)
  2. JQuery------各种版本下载
  3. StringUtils.isBlank()检验String 类型的变量是否为空
  4. kindeditor编辑器和图片上传独立分开的配置细节
  5. 用matlab交互式的选取图像特定区域数据
  6. Android WebView 开发详解(三)
  7. 少儿德国奎尔鱼油(QÜELL FISH OIL FOR JUNIOR )
  8. Django框架基础知识05-自定义模板标签与过滤器
  9. 弱类型、强类型、动态类型、静态类型语言的区别
  10. It is possible that this issue is resolved by uninstalling an existi