C#学习笔记:值类型与引用类型(详解)


这个问题应该是困扰任何一门语言初学者的问题,为此整理了网上的一些资料,希望能为大家解惑。

首先对于C#中的数据类型,只有两种,不是值类型就是引用类型。

值类型:结构体(数值类型,bool型,用户定义的结构体),枚举,可空类型

引用类型:数组,用户定义的类、接口、委托,object,字符串。

从表面的概念上看,值类型是直接存储其值,而引用类型存储的是对值的引用。

从存储在内存的位置来看,值类型是存储在堆栈(线程堆栈)上,而引用类型是存储在托管堆上。

(事实上,对于新手来说,也没有必要去细究堆栈和托管堆是什么,只需要知道是内存中的两块不同的区域就可以了,但为了保持严谨的治学态度,我建议大家可以参考:http://www.cnblogs.com/axzxs2001/archive/2008/08/28/1279037.html


讲这些内容还是比较晦涩的,下面通过一个示例讲解:

 1//引用类型SomeRef
 2
 3    class SomeRef
 4
 5  {
 6
 7        public Int32 x;
 8
 9    }

10
11    //值类型SomeVal
12
13    struct SomeVal
14
15  {
16
17        public Int32 x;
18
19    }

20
21    static void ValueTypeDemo()
22
23  {
24
25        SomeRef r1 = new SomeRef();//在托管堆上分配
26
27        SomeVal v1 = new SomeVal();//在堆栈上分配
28
29        r1.x = 5;                  //提领指针
30
31        v1.x = 5;                  //在堆栈上实际修改
32
33        Console.WriteLine(r1.x);   //显示5
34
35        Console.WriteLine(v1.x);   //显示5
36
37 
38
39
40        //以上代码为图的左边部分,以下代码为右边部分
41
42 
43
44
45        SomeRef r2 = r1;           //只复制引用()
46
47        SomeVal v2 = v1;           //在堆栈上分配并复制成员 
48
49        r1.x = 8;                  //修改r1.x和r2.x  
50        v1.x = 9;                  //只修改v1.x而不修改v2.x
51        Console.WriteLine(r1.x);   //8        
52        Console.WriteLine(r2.x);   //8        
53        Console.WriteLine(v1.x);   //9
54        Console.WriteLine(v2.x);   //5
55
56    }

57
58


事实上通过这个示例,大家已经可以很清晰的区分值类型与引用类型的一些区别了,尤其关于赋值的问题:值类型赋值是通过值的复制来实现的,修改新的变量的值对原变量没有影响,而引用类型的赋值实际上是赋予给对象的引用,修改任何一个的值实际上修改了其引用,所有指向这个引用的变量的值都会发生改变。

但有时候你会发现这样的问题:

string s1 = "hello";
string s2 = s1;
Console.WriteLine(s1);    
//hello
Console.WriteLine(s2);    //hello
s1="goodbye";
Console.WriteLine(s1);    
//goodbye
Console.WriteLine(s2);    //hello


刚才我们也提到string类型属于引用类型,又根据引用类型值的特点,这里修改s1的值后,s2的值应该发生改变才对?
事实上这里并不矛盾,原因在于当改变s1的值是,实际上新创建了一个string对象,s1引用这个新的string对象;s2仍然引用原来string对象。产生这种行为的原因是string对象是恒定的,也就是说,一旦一个string对象被创建,它的值就不能再修改,所以当改变一个字符串变量的值的时候,仅仅是新创建了一个包含修改内容的新的string对象。这点大家要特别注意。

补充:

设计自己的类型时,是考虑使用值类型还是引用类型,某些时候,值类型比引用类型有更好的性能。以下几种情况应该考虑使用值类型:

(1)类型具有一个基元类型的行为,也就是这是一个非常简单的类型,其中没有成员会修改类型的任何字段。

(2)类型不需要从其它任何类型继承也不会派生出其它任何类型

(3)类型的实例较小,约为16字节或更小 

(4)类型的实例较大,大于16字节,但不作为方法传递,也不作为方法的返回类型使用


参考文章:http://www.cnblogs.com/chenzehe/archive/2009/01/30/1381073.html
http://blog.csdn.net/canduecho/archive/2008/01/13/2042509.aspx






 

posted @ 2009-10-13 12:06  Jason.z  阅读(665)  评论(0编辑  收藏  举报