首页 ┆ 网站地图 ┆ 在线留言 ┆ 游戏资讯 ┆ 资源下载 ┆ 端午节祝福 ┆ 迅雷在线影视 ┆淘宝手机在线充值 ┆淘宝游戏点卡充值 
设为首页
加入收藏
联系我们
高级搜索
您当前的位置: 主页>NET专区>C#语言>什么是装箱和拆箱?及其相应的操作事例
什么是装箱和拆箱?及其相应的操作事例
来源: 发布时间:2008-04-02 发布人: 浏览: 人次   字体: [ ]  
首先介绍装箱(Boxing)和拆箱(Unboxing)这两个名词。.Net的类型分为两种,一种是值类型,另一种是引用类型。这两个类型的本质区别,值类型数据是分配在栈中,而引用类型数据分配在堆上。那么如果要把一个值类型数据放到堆上,就需要装箱操作;反之,把一个放在堆上的值类型数据取出来,则需要进行拆箱操作。

 

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

    int i = 123;

    object obj = i;//Boxing

 

    if( obj is int )

        int  j = (int) obj;//Unboxing

 

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

 

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

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

 

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

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

例如:

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

        1,2,3 );

 

对于“123”来说,相当于前面的“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;

        }

 

    }

 

    ArrayList arrPersons = new ArrayList();

    Person p = new Person( "OldName" );

    arrPersons.Add( p );

   

   

    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] )”来说,是系统用一个临时变量来接收拆箱后的值类型数据,那么由于值类型是分配在栈上,那么操作是对实体操作,可是系统不允许对一个临时值类型数据进行修改操作。

   

    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;

        }

    }

  

    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,属于引用类型,那么相当于临时变量就是原对象的引用,那么对于对于它的修改会直接修改到原对象,因此是可以的。可以说这里的不同本身在于产生临时对象的类型不同,从而造成本质的区别。

 

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

 

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


相 关 文 章   发布商链接
·C#获取IE临时文件夹中的文件代码
·什么是c#深拷贝与浅拷贝及其代码示例
·c#访问修饰符介绍及其应用实例
·C#如何获取文件路径中的文件名?
·c#子线程控制进度条的一个简单例子
·什么是泛型编程思想?及其简单的应用...
·如何使用C#获取IIS服务器版本?
·如何在c#中去掉字符串中的回车符?
·C#如何从文本文件读取信息并使用Arra...
·什么是泛型?泛型的一些概述
 §最新评论:(评论内容只代表网友观点,与本站立场无关!)
网名: 验证码:  【所有评论】【↑返回顶部
评 分: 12 345
评论内容:(不能超过500字,请自觉遵守互联网相关政策法规。[按 Ctrl+Enter 可直接提交]
注意:请勿在本站发布政治话题、色情及违反法律的内容。
IT知道网 声明:刊登此文章是为了传递更多信息,文章内容仅供参考,转载请注明出处。
推 荐 文 章
·最为经典的C#操作文件的方法...
·有助快速理解C#委托和事件之...
·C#泛型学习笔记总结
·c#语言从dbf数据库提取数据并
·C#编写控制线程的运行和线程...
·怎样在C#中删除只读文件及其...
·C#函数中返回多个值的两种方...
·如何在C#中插入照片到Excel文
·如何在c#中获取事件注册的方...
·C#对timer类的使用操作代码
·什么是泛型?泛型的一些概述
·C#如何从文本文件读取信息并...
·如何在c#中去掉字符串中的回...
·如何使用C#获取IIS服务器版本...
·什么是泛型编程思想?及其简...
热 门 文 章
·C#如何获取文件路径中的文件...
·c#中收发邮件处理代码(POP3,...
·浅谈接口和抽象类的区别,加...
·什么是c#深拷贝与浅拷贝及其...
·C#语言实现创建、删除和移动...
·C#中关于四舍五入函数的讨论...
·c#中的ArrayList属性祥解及其...
·快速进行List排序的通用方法...
·C#对timer类的使用操作代码
·C#如何从文本文件读取信息并...
·C#语言实现从XML文件导出数据...
·用C#编写ActiveX控件代码实例
·如何在c#中去掉字符串中的回...
·String.Split 方法使用及其代...
·C#语言绘制实时曲线图代码实...
网站首页 - 关于本站 - 加入收藏 - 网站地图 - 友情连接 - 在线留言 - 联系我们 - 返回顶部
Copyright © 2007 IT知道网.[冀ICP备07026896号]. All Rights Reserved .