代码改变世界

C#基础回顾之1——值类型与引用类型

2008-07-31 02:13  JimLiu  阅读(391)  评论(1编辑  收藏

C#基础回顾之1——值类型与引用类型

C#的数据类型最终可以分为两种,那就是值类型(Value Type)和引用类型(Reference Type)。简单地说,在参数传递的过程中,引用类型按引用传递,值类型按值传递(拷贝传递)。

什么类型是引用类型,什么类型是值类型呢?说简单点,类类型是引用类型,继承自System.Object;基本数据类型、自定义结构体和枚举类型是值类型,继承自System.Object.ValueType

在申请空间的时候,值类型被CLR放在栈上,方便随着函数调用栈的进程而自动弹出(并销毁)掉值类型;而引用类型被放在托管堆上,以便CLR的垃圾回收机制能正确地管理内存。

下图表示了.NET类库中的值类型

 

   

   

有一个很有趣的类型,任何人都会用到它,但却有很多人对它有误解,那就是System.String。当我们通过函数参数传递一个字符串的时候,它的值并不会被修改,这让字符串“看起来”像一个值类型。但事实上字符串是地地道道的引用类型,.NET运行库在这里耍了一个小把戏,在运行时有一个“字符串池”,每个字符串都唯一地存在于字符串池中。由于.NET类库中的字符串是不可修改的,我们每修改一个字符串都是在创建新的字符串,所以在参数传递的时候,字符串是不会被修改的,这让字符串看起来像一个值类型。

在我们声明一个值类型的时候,它默认就继承了System.Object.ValueType,并且隐含地标注了它为Sealed,表示它不可被继承。

注意:如果我们声明了一个结构体,它有某个成员是引用类型,那么在按值传递这个结构的实例的时候,它的成员是按引用传递的,也就是说在传参拷贝的时候执行的是浅拷贝!

由于值类型分配在栈上,而不是托管堆上,因此它的回收是不由CLR垃圾回收机制来处理的,所以我们无法为值类型重写System.Object.Finalize()方法。实际上,就算我们能重写,它也永远起不到作用。

我们可以为自定义结构体重载构造函数,但是与自定义类不同,为自定义结构重载构造函数必须带参数,也就是说,无法重载默认构造函数!

值类型和引用类型最终都继承自System.Object这个抽象基类(事实上,这是.NET环境中所有类型的基类),也就是说,任何类型都可以转换为System.ObjectSystem.Collections命名空间下的容器正是利用了这点。但是有一点不同的就是,当把一个值类型转换为引用类型(或者反过来)的时候,会执行装箱(boxing)或拆箱(unboxing)。当一个值类型被转换为引用类型的时候,系统会进行装箱操作;反过来,当一个引用类型被转换为值类型的时候,会进行拆箱操作。这一点以后的文章中会讲到。