c#中值类型和引用类型解析

  

在c#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为。如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常。很多人就是因为没有弄清楚这两个概念从而在编程过程中遇到了很多问题,在这里博主浅谈对值类型和引用类型的认识。

  

首先从概念上看,值类型直接存储其值,而引用类型存储对其值的引用。从而这两种类型存储在内存的不同地方。

  

其次从内存空间上看,值类型是在栈中操作,而引用类型则在堆中分配存储单元。

  

栈在编译的时候就分配好内存空间,在代码中有栈的明确定义,而堆是程序运行中动态分配的内存空间,可以根据程序的运行情况动态地分配内存的大小,因此,值类型总是在内存中占用一个预定义的字节数。而引用类型的变量则在栈中分配一个内存空间,这个内存空间包含的是对另一个内存位置的引用,这个位置是托管堆中的一个地址,即存放此变量实际值的地方。

  

也就是说值类型相当于现金,要用就直接用,而引类型相当于存折,要用得先去银行取。

  

但值类型在栈上分配内存,而引用类型在托管堆上分配内存,只是一种笼统的说法。下面对其进行详细描述。

  

(1)对于值类型的实例,如果作为方法中的局部变量,则被创建在线程栈上,如果该实例作为类型的成员,则作为类型成员的一部分,连同其他类型字段存放在托管堆上。

  

每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。例如:

        int i=new int ();   之前      

等价于:

        新Int32 Int32 i=();   之前      

等价于:

        int i=0;   之前      

等价于:

        Int32我=0;   之前      

使用新运算符时,将调用特定类型的默认构造函数并对变量赋以默认值。在上例中,默认构造函数将0值赋给了我。

  

说明:c#的所有值类型均隐式派生自System.ValueType,而System.ValueType直接派生于System.Object。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了等于方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

  

(2)引用类型的实例创建在托管堆上。

  

下面以一段代码来详细讲解一下值类型与引用类型的区别

        名称空间测试   {   类项目   {   静态void Main (string [] args)   {//调用ReferenceAndValue类中演示的方法   ReferenceAndValue.Demonstration ();   Console.ReadLine ();   }   }   公共类邮票//定义一个类   {   公共字符串名称{;设置;}//定义引用类型   公共int年龄{得到;设置;}//定义值类型   }   公共静态类ReferenceAndValue//定义一个静态类   {   公共静态空白演示()//定义一个静态方法   {   新邮票邮票Stamp_1={Name=笆籽荨?25岁};//实例化   新邮票邮票Stamp_2={Name=霸俅巍?年龄=47};//实例化   int年龄=Stamp_1.Age;//获取值类型年龄的值   Stamp_1。年龄=22;//修改值类型的值   邮票大师=Stamp_2;//获取Stamp_2中的值   Stamp_2。Name="再次修改”;//修改引用值的名称   控制台。WriteLine (Stamp_1的年龄:{0},Stamp_1.Age);//显示Stamp_1中值的年龄   控制台。WriteLine(年龄的价值:{0},年龄);//显示年龄值   控制台。WriteLine (Stamp_2的名字:{0},Stamp_2.Name);//显示Stamp_2中值的名称   控制台。WriteLine(“大师的名字:{0}”,guru.Name);//显示大师中值的名称   }   }   }      

通过运行上面一段程序之后我们可以看的出,当改变了Stamp_1.Age的值时,年龄并没有跟着变,但在改变了anders.Name的值后,大师。的名字却跟着变了,这就是值类型和引用类型的区别。在声明年龄值类型变量时,将Stamp_1.Age的值赋给它,这时,编译器在栈上分配了一块空间,然后把Stamp_1.Age的值填进去,二者没有任何关联,就像在计算机中复制文件一样,只是把Stamp_1.Age的值拷贝给年龄了。而引用类型则不同,在声明大师时把Stamp_2赋给它,前面说过,引用类型包含的只是堆上数据区域地址的引用,其实就是把Stamp_2的引用也赋给大师,因此它们指向了同一块内存区域,既然是指向同一块区域,不管修改谁,另一个的值都会跟着改变,就像信用卡跟亲情卡一样,用亲情卡取了钱,与之关联的信用卡账上也会跟着发生变化。

c#中值类型和引用类型解析