All articles| All Pictures| All Softwares| All Video| Go home page| Write articles| Upload pictures

Reading number is top 10 articles
网页屏蔽(左右键,代码等)的非JS方法总结_JavaScript技术_编程技术
编写SQL查询的关键—SQL语句的执行顺序_mssql学习_编程技术
五个常见 PHP 数据库问题_[PHP教程]
C#中的PrintDocument组件的属性的应用实例
Php高手带路--问题汇总解答_php资料_编程技术
ASP.NET技巧:做个DataList,可分页的数据源_[Asp.Net教程]
JS代码的格式化和压缩_JavaScript技术_编程技术
怎么样学习PHP_[PHP教程]
SQL备份语句_mssql学习_编程技术
SQL循序渐进(3)-------数据检索_[SQL,Server教程]
Reading number is top 10 pictures
超强高考作文
From China fortress sora aoi1
夕阳下的北京街道
男人帮杂志里的惹火性感美女2
含苞欲放的素颜美少女2
30 beautiful school beauty3
Average female college students1
俞敏洪在清华终于说了实话
玩手机对身体不好
No trading, no killing
Download software ranking
Eclipse 4.2.1 For Win32
White deer villiage
jBuilder2006
Unix video tutorial13
Dance with duck(male prostitution)
Tram sex maniac 2 (H) rar bag2
星际争霸1.08硬盘免安装版
linux安装大全
Tram sex maniac 2 (H) rar bag4
Tram sex maniac 2 (H) rar bag6
delv published in(发表于) 2014/1/24 9:10:23 Edit(编辑)
《Effective,C#》之减少装箱和拆箱_[Asp.Net教程]

《Effective,C#》之减少装箱和拆箱_[Asp.Net教程]

《Effective C#》之减少装箱和拆箱_[Asp.Net教程]

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

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

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

出处:天极Yesky 作者:愚翁






添加到del.icio.us 添加到新浪ViVi 添加到百度搜藏 添加到POCO网摘 添加到天天网摘365Key 添加到和讯网摘 添加到天极网摘 添加到黑米书签 添加到QQ书签 添加到雅虎收藏 添加到奇客发现 diigo it 添加到饭否 添加到飞豆订阅 添加到抓虾收藏 添加到鲜果订阅 digg it 貼到funP 添加到有道阅读 Live Favorites 添加到Newsvine 打印本页 用Email发送本页 在Facebook上分享


Disclaimer Privacy Policy About us Site Map

If you have any requirements, please contact webmaster。(如果有什么要求,请联系站长)
Copyright ©2011-
uuhomepage.com, Inc. All rights reserved.