C# 类型基础
装箱和拆箱
这部分内容可深可浅,本文只简要地作一个回顾。简单来说,装箱 就是 将一个值类型转换成等值的引用类型。它的过程分为这样几步:
- 在堆上为新生成的对象(该对象包含数据,对象本身没有名称)分配内存。
- 将 堆栈上 值类型变量的值拷贝到 堆上的对象 中。
- 将堆上创建的对象的地址返回给引用类型变量(从程序员角度看,这个变量的名称就好像堆上对象的名称一样)。
当我们运行这样的代码时:
int i = 1;
Object boxed = i;
Console.WriteLine("Boxed Point: " + boxed);
效果图是这样的:
MSIL代码是这样的:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 代码大小 19 (0x13)
.maxstack 1 // 最高栈数是1,装箱操作后i会出栈
.locals init ([0] int32 i, // 声明变量 i(第1个变量,索引为0)
[1] object boxed) // 声明变量 boxed (第2个变量,索引为1)
IL_0000: nop
IL_0001: ldc.i4.s 10 //#1 将10压栈
IL_0003: stloc.0 //#2 10出栈,将值赋给 i
IL_0004: ldloc.0 //#3 将i压栈
IL_0005: box [mscorlib]System.Int32 //#4 i出栈,对i装箱(复制值到堆,返回地址)
IL_000a: stloc.1 //#5 将返回值赋给变量 boxed
IL_000b: ldloc.1 // 将 boxed 压栈
// 调用WriteLine()方法
IL_000c: call void [mscorlib]System.Console::WriteLine(object)
IL_0011: nop
IL_0012: ret
} // end of method Program::Main
而拆箱则是将一个 已装箱的引用类型 转换为值类型:
int i = 1;
Object boxed = i;
int j;
j = (int)boxed; // 显示声明 拆箱后的类型
Console.WriteLine("UnBoxed Point: " + j);
需要注意的是:UnBox 操作需要显示声明拆箱后转换的类型。它分为两步来完成:
- 获取已装箱的对象的地址。
- 将值从堆上的对象中拷贝到堆栈上的值变量中。