问题 | 值类型 | 引用类型 |
举例 | 例如:int、float、bool之类的基础类型,以及用struct定义的类型,如:DateTime。 | 如string,数组,以及用class定义的类型等都是引用类型 |
这两个类型分别分配在哪里 | 分配内联(栈)上 | 分配在托管堆上 |
在这两个类型中变量是怎么表示的 | 局部复制 | 指向被分配的实例所占的内存 |
基类是什么 | 必须继承自System.ValueType | 可继承除了System.ValueType以外的任何非密封的类型 |
是否可以作为其他类型的基类 | 不能。值类型总是密封的,不能被继承 | 可以。前提是该类型不是密封的 |
默认的参数传递行为是什么 | 是对象的复制,按值传递(即:一个变量的副本被传入被调用的函数) | 是原有对象的引用,并不产生新的对象。按引用传递(例如:变量的地址传入被调用的函数) |
能否为这两个类型定义构造函数 | 可以。但是,自定义构造函数必须全部带参数 | 可以 |
这两个类型的变量什么时候消亡 | 超出其作用域时,使用完后,立即回收 | 使用完后,不是立即回收,等待GC回收 |
默认值是 | 0 | Null |
效率 | 效率高,不需要地址转换 | 效率低,需要地址转换 |
类型扩展 | 不易扩展 | 容易扩展,方便与类型扩展 |
对于值类型来说,当其 作为函数参数的时候,希望在函数中被修改,那么直接如下操作是不能被修改的: 1. public void Increment( int i ) 2. { 3. i++; 4. } 要想在函数中对传进去的参数做真正的修改,需要借助于ref这个关键字,那么正确的形式如下: 1. public void Increment( ref int i ) 2. { 3. i++; 4. } 也就是说,如果需要在函数中对值类型参数进行修改,需要用ref或者out进行标识才能真正实现。 | 对于引用 类型来说,当其作为函数参数的时候,它所遇到的情况恰恰与值类型相反,即不希望在函数中被修改,举例如下: 为了防止这种事发生,需要给此类型提供clone函数。例如对 于如上的类型,可以入下实现 : 不过对于引用类型来说,提供一个clone函数不是一 件容易的事情,尤其出现引用类型嵌套的时候,所以说去实现一个完全clone功能是件很费事又不讨好的活,这也就是在论坛中常说的深copy和浅copy 的问题。话虽如此,如果对于前面所说的有个大概了解,相信实现也不是不可能。 在C#中,尤其自己定义类型的时候,常常由于是用 struct来定义还是用class来定义,即是定义一个值类型还是一个引用类型呢。在这本书上给了几个判定条件,如果如下几点都满足的话,建议用 struct来定义为值类型,否则用class定义为引用类型。 |