C# 值类型与引用类型

值类型与引用类型

只所以要提这两个概念,是因为很好得理解这两个概念有助于我们写出比较高效的C#代码。

我们知道,C#中的每一种类型要么是值类型,要么是引用类型。所以每个对象要么是值类型的实例,要么是引用类型的实例。

引用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即直接继承System.ValueType。

作为所有类型的基类,System.Object提供了一组方法,这些方法在所有类型中都能找到,其中包含toString方法及clone等方法。

System.ValueType直接继承System.Object,即System.ValueType本身是一个类类型,而不是值类型;System.ValueType没有添加任何成员,但覆盖了所继承的一些方法,使其更适合于值类型。例如,ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

C# 值类型与引用类型

简单了解了值类型与引用类型那么我们下面来看下C#中的装箱和拆箱的概念。

装箱和拆箱

装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作。

1.    装箱在值类型向引用类型转换时发生

2.    拆箱在引用类型向值类型转换时发生

1 object objValue = 4;

2

3 int value = (int)objValue;

  

上面的两行代码会执行一次装箱操作将整形数字常量4装箱成引用类型object变量objValue;然后又执行一次拆箱操作,将存储到堆上的引用变量objValue存储到局部整形值类型变量value中。

同样我们需要看下IL代码:

C# 值类型与引用类型

C# 值类型与引用类型

 1 .locals init (

 2

 3 [0] object objValue,

 4

 5 [1] int32 'value'

 6

 7 ) //上面IL声明两个局部变量object类型的objValue和int32类型的value变量

 8

 9 IL_0000: nop

10

11 IL_0001: ldc.i4.4 //将整型数字4压入栈

12

13 IL_0002: box [mscorlib]System.Int32 //执行IL box指令,在内存堆中申请System.Int32类型需要的堆空间

14

15 IL_0007: stloc.0 //弹出堆栈上的变量,将它存储到索引为0的局部变量中

16

17 IL_0008: ldloc.0//将索引为0的局部变量(即objValue变量)压入栈

18

19 IL_0009: unbox.any [mscorlib]System.Int32 //执行IL 拆箱指令unbox.any 将引用类型object转换成System.Int32类型

20

21 IL_000e: stloc.1 //将栈上的数据存储到索引为1的局部变量即value

C# 值类型与引用类型

C# 值类型与引用类型

 

拆箱操作的执行过程和装箱操作过程正好相反,是将存储在堆上的引用类型值转换为值类型并给值类型变量。