一、基本概念
c#只有两种数据类型:值类型和引用类型
值类型在线程栈分配空间,引用类型在托管堆分配空间
值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱
以下是值类型和引用类型对照表
从上图可以简单看出:string,object,数组,class是引用类型,简单类型,枚举,结构是值类型。
二、代码展示
定义一个类和结构调用赋值
内存分配情况如下图:
从这张图可以看出,class实例化出来的对象,指向了内存堆中分配的空间;truct实例化出来的对象,是在内存栈中分配。
修改代码如下:
内存分配情况:
由上图可以知:
object obj=”abc”;
string i=(string)obj;
值类型和引用类型储的位置不一样
如果是引用类型,当两个对象指向同一个地方,修改某一个的时候,其它对象的值会发生改变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
using system;
namespace consoleapplication2
{
//引用类型(因为‘class')
public class someref
{
public int x { get ; set ; }
}
//值类型(因为‘struct')
public struct someval
{
public int x{ get ; set ; }
}
class program
{
static void main( string [] args)
{
someref r1= new someref(); //在堆上分配
someval v1 = new someval(); //在栈上分配
r1.x = 5; //提领指针
v1.x = 5; //在栈上修改
console.writeline(r1.x); //显示5
console.writeline(v1.x); //显示5
someref r2 =r1; //只复制引用(指针)
someval v2 =v1; //在栈上分配并赋值成员
r1.x = 8; //r1.x和r2.x都会修改
v1.x = 8; //v1.x会更改,v2.x不会
console.writeline(r1.x); //显示8
console.writeline(r2.x); //显示8
console.writeline(v1.x); //显示8
console.writeline(v2.x); //显示5
console.readkey();
}
}
}
|
三、值类型装箱、拆箱
1、装箱:就是将值类型的数据打包到引用类型的实例中(比如将string类型的值abc赋给object对象obj)
object obj=(object)i;
装箱时到底发生的事情:
1)、在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量
2)、值类型的字段复制到新分配的堆内存
3)、返回对象地址,现在该地址是对象引用;值类型成了引用类型
2、拆箱:就是从引用数据中提取值类型(比如将object对象obj的值赋给string类型的变量i)
string i=(string)obj;
拆箱不是装箱过程倒过来,拆箱的代价爱比装箱低的多,拆箱是获取指针的过程,该指针指向包含在一个对象中的原始值类型。
拆箱后将堆中的字段包含的值复制栈的值类型实例中。
3、值类型变为引用类型不一定要装箱,例如:
string str1 = "joye.net" + 26.tostring(); //tostring后不需要装箱
感兴趣的可以用il看一下。