值类型的拆箱和装箱
来源:互联网 发布:vue.js 左右滑动div 编辑:程序博客网 时间:2024/05/22 00:36
关于值类型的一个实例进行装箱操作时内部发生的事情如下:
1) 在托管堆中分配好内存。分配的内存量是值类型的各个字段需要的内存量加上托管堆的所有对象都有的两个额外成员(类型对象指针和同步块索引)需要的内存量。
2)值类型的字段复制到新分配的堆内存。
3)返回对象的地址。这个地址是一个对象的引用,值类型现在是一个引用对象。
C# 编译器会自动生成对一个值类型的实例进行装箱所需要的IL代码,但你仍然需要理解内部发生的事情,否则很容易忽视代码长度和性能问题。
拆箱步骤如下:
1)获取已装箱的对象中各个字段的地址。
2)将这些字段包含的值从堆中复制到基于栈的值类型实例中。
举个例子如下:
using System.Collections.Generic;using System.Linq;using System.Text;namespace BoxAndUnBoxProject{ class Program { static void Main(string[] args) { Int32 v = 5; Object o = v;//o引用一个已装箱的包含5的int32 v = 123; Console.WriteLine(v+","+(Int32)o); } }}
从上述代码可以看出发生了3次装操作。第一次发生在Object o=v;第二次发生在v对object转换,第三次对(Int32)o 拆箱后在装箱。这才是真正的装箱,而不是所为的对v转换为ToString()装箱。
为了验证我的思想对不对,咱们先看下IL生成的代码,可以通过IL反编译器查看。如下:
using System.Collections.Generic;using System.Linq;using System.Text;namespace BoxAndUnBoxProject{ class Program { static void Main(string[] args) { Int32 v = 5; string str = v.ToString(); //Object o = v;//o引用一个已装箱的包含5的int32 //v = 123; //Console.WriteLine(v+","+(Int32)o); } }}
IL反编译代码如下:
.method private hidebysig static void Main(string[] args) cil managed{ .entrypoint // 代码大小 12 (0xc) .maxstack 1 .locals init ([0] int32 v, [1] string str) IL_0000: nop IL_0001: ldc.i4.5 IL_0002: stloc.0 IL_0003: ldloca.s v IL_0005: call instance string [mscorlib]System.Int32::ToString() IL_000a: stloc.1 IL_000b: ret} // end of method Program::Main
上述代码转换string的时候没有发生装箱操作,因为木有box关键字。(不是所有的调用ToString()都不发生装箱操作,这里没有是因为Int32这个类override了ToString()方法,所以没有装箱操作。)
现在回归到第一次代码的反编译代码如下:
.method private hidebysig static void Main(string[] args) cil managed{ .entrypoint // 代码大小 47 (0x2f) .maxstack 3 .locals init ([0] int32 v, [1] object o) IL_0000: nop IL_0001: ldc.i4.5 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: box [mscorlib]System.Int32 IL_0009: stloc.1 IL_000a: ldc.i4.s 123 IL_000c: stloc.0 IL_000d: ldloc.0 IL_000e: box [mscorlib]System.Int32 IL_0013: ldstr "," IL_0018: ldloc.1 IL_0019: unbox.any [mscorlib]System.Int32 IL_001e: box [mscorlib]System.Int32 IL_0023: call string [mscorlib]System.String::Concat(object, object, object) IL_0028: call void [mscorlib]System.Console::WriteLine(string) IL_002d: nop IL_002e: ret} // end of method Program::Main
在IL_0004阶段 把Int32 v 装箱并加载到Object o 中,有box关键字。
看IL_0023阶段调用的是string.Concat(object,object,object) 方法,此时要对Int32 v 和(Int32)o 进行装箱操作,至于string “,” 它本身就是一个特殊的引用类型,而无需进行装箱操作。下图进行完整解析:
这是完整的装箱和拆箱的过程 。所以对我们而言,能显示拆箱和装箱的就进行显示进行,这样更能提高效率,但是装箱和拆箱尽量少用,因为这玩意会占用大量的内存,对性能也有所影响。只有深刻理解了拆箱和装箱操作,才能更快、更轻松地构建高效率的应用程序。
那么下面装了几次箱:
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace BoxAndUnBoxProject{ class Program { static void Main(string[] args) { Int32 v = 5; Object o = v; Console.WriteLine(o.ToString()); } }}
- 值类型的拆箱和装箱
- 类型的装箱和拆箱
- 值类型变量的装箱和拆箱
- [C#] 值类型的装箱和拆箱
- 引用类型和值类型(装箱和拆箱)
- 值类型和引用类型间的转换-装箱和拆箱
- 值类型和引用类型的转换(装箱和拆箱)
- 6个重要的.NET概念: - 堆栈,堆,值类型,引用类型,装箱和拆箱
- 基本类型的自动装箱和拆箱
- java引用类型数组的装箱和拆箱
- 值类型、引用类型、拆箱装箱
- 栈和托管堆/值类型和引用类型/强制类型转换/装箱和拆箱
- 变量,常量,引用类型,值类型,枚举类型, 值类型和引用类型的简单区别,类型转换,装箱与拆箱
- C#基础知识整理 基础知识(18) 值类型的装箱和拆箱(一)
- C#基础知识整理 基础知识(19) 值类型的装箱和拆箱(二)
- c# 值类型和引用类型的区别,装箱,拆箱。
- 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
- 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
- 第二周项目4用循环求
- linux open too many files
- 第二周项目3-小试循环
- 第二周项目-就拿胖子说事
- c++第一次上机报告1
- 值类型的拆箱和装箱
- 第2周项目1宣告主权
- C++第一次上机实验-1
- c++作业1
- 用循环求(1)
- ubuntu 程序后台运行几个方法
- 走近科学:二维码真的安全吗
- Java并发编程:线程间协作的两种方式
- 淘宝大秒系统设计详解