知识点
- 值类型。
- 值类型是在栈中分配内存,在声明时初始化才能使用,不能为null。
- 值类型超出作用范围系统自动释放内存。
- 主要由两类组成:结构,枚举(enum),结构分为以下几类:
- 整型(Sbyte、Byte、Char、Short、Ushort、Int、Uint、Long、Ulong)
- 浮点型(Float、Double)
- decimal
- bool
- 用户定义的结构(struct)
- 引用类型。
- 引用类型在堆中分配内存,初始化时默认为null。
- 引用类型是通过垃圾回收机制进行回收。
- 包括类、接口、委托、数组以及内置引用类型object与string。
概念
由于C#中所有的数据类型都是由基类System.Object继承而来的,所以值类型和引用类型的值可以通过显式(或隐式)操作相互转换,而这转换过程也就是装箱(boxing)和拆箱(unboxing)过程。
- 装箱 是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换(就算实现了某个接口,转为接口依旧要装箱)。对值类型装箱会在堆中分配一个对象实例,并将该值复制到新的对象中。
- 拆箱(取消装箱)是从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。取消装箱操作包括:
-
检查对象实例,确保它是给定值类型的一个装箱值。(拆箱后没有转成原类型,编译时不会出错,但运行会出错,所以一定要确保这一点。用GetType().ToString()判断时一定要使用类型全称,如:System.String 而不要用String。)
-
将该值从实例复制到值类型变量中。
-
示例
首先写个简单的控制台程序:
// Tutorial_boxing_unboxing.cs // 装箱与拆箱 using System; class App { static void Main() { int i = 32; object o = i; //隐式装箱 Console.WriteLine("o = {0}", o); Console.Read(); } }
其中object o = i这里我们进行了装箱操作,然后我们用MSIL 反汇编程序查看下生成的.exe程序的内部机理。
1 .method private hidebysig static void Main() cil managed 2 { 3 .entrypoint 4 // 代码大小 30 (0x1e) 5 .maxstack 2 6 .locals init ([0] int32 i, 7 [1] object o) 8 IL_0000: nop 9 IL_0001: ldc.i4.s 32 10 IL_0003: stloc.0 11 IL_0004: ldloc.0 12 IL_0005: box [mscorlib]System.Int32 13 IL_000a: stloc.1 14 IL_000b: ldstr "o = {0}" 15 IL_0010: ldloc.1 16 IL_0011: call void [mscorlib]System.Console::WriteLine(string, 17 object) 18 IL_0016: nop 19 IL_0017: call int32 [mscorlib]System.Console::Read() 20 IL_001c: pop 21 IL_001d: ret 22 } // end of method App::Main
其中第12行是我们的装箱操作。(关于IL中出现的操作符代表的操作请查阅MSDN Library中的.NET开发/.NET Framework SDK/类库参考/System.Reflection.Emit/OpCodes 类/OpCodes 字段)