C#中变量类型的区别与使用总结-新闻详情

C#中变量类型的区别与使用总结


发布时间:2016-08-31责任编辑:朱明 浏览:1587


一、值类型与引用类型的区别

在C#中,变量分为两种类型,分别是值类型(ValueType)与引用类型(ReferenceType)。值类型变量直接存储值,即在内存中直接保存它自身的值。例如:

 

int a = 2;

 

值类型变量a,在内存中的某处保存了它自身的值:2。引用类型变量存储的是对象的引用(地址),即在内存中保存了一个指向它处的引用,在该地址存储了引用所指的对象。例如:

 

public class Example

{

     //...

}

Example example = new Example();

 

引用类型变量example,对它进行声明时,会在内存中分配一块空间保存它的内容,而我们所使用的变量example,它实际上是一个指向自身内容的引用。对于如何判断一个变量是值类型还是引用类型,我们稍后会谈到。接下来,让我们了解一下在C#中值类型与引用类型的变量都有哪些区别,这些区别能够帮助我们分辨一个变量是值类型,还是引用类型。

 

1、值类型变量不能为空,而引用类型变量可以为空(null)。因为值类型变量直接保存它自身的值,并且它总是包含一个值(有默认值存在),所以不能为空。引用类型变量保存的是一个指向它处的引用,当它为空时,表示该变量未指向内存中的任何地方。

2、引用类型直接继承自Systen.Object类,而值类型直接继承自System.ValueType类。System.Object类作为所有类型的基类,它提供了一组方法,这些方法在所有类中都能找到,例如ToString()等。System.ValueType类继承了System.Object类,它并没有添加任何新成员,只是覆盖了所继承的一些方法,使其更适合于值类型。我们可以通过Type.IsValueType属性来判断一个类型是否为值类型。例如:

 

Example example = new  Example();

if (example.GetType().IsValueType)

{

     //...

}

else 

{

     //...

}

 

3、引用类型变量和值类型变量,它们在内存中的存储分配规则不同。引用类型变量总是分配在堆中,值类型变量可能分配在堆中,也可能分配在栈中,这与它们被声明的位置相关。若值类型变量作为类的字段被声明,那么它将跟随其所属的对象被分配到堆中;若值类型变量作为方法内的本地变量被声明,那么它将存储在栈上。例如:

 

public class Example

{

     int a;//a是值类型变量,它作为Example类的字段被声明,将跟随引用类型对象被分配,位于堆上。

     

     public void Test()

     {

          int b = 1;//b是值类型变量,它作为Test方法的本地变量,位于栈上。

     }

}

Example example = new Example();

 

4、所有的值类型都是密封的(seal),无法派生出新类型。而引用类型则可以继续派生。这也是值类型适合存储数据,引用类型适合定义行为的原因。以下是C#中值类型与引用类型的详细划分列表:

 

作为值类型的数据类型

作为引用类型的数据类型

bool

class

byte

object

char

string

decimal

interface

double

delegate

float


int


long


short


sbyte


uint


ulong


ushort


enum


struct


 

二、值类型、引用类型变量与内存中堆和栈的关系

我们在上面谈到,引用类型变量与值类型变量在内存中具有不同的分配规则,它们涉及到内存中堆与栈的使用问题,对代码的执行效率有不小的影响。下面我们就堆与栈的问题做一番说明。

堆(Heap)与栈(Stack),是内存中的不同区域。在内存中栈负责保存代码的执行路径(调用路径)。当我们的代码开始调用一个方法时,首先将一段指令放置到栈上,接下来放置方法的参数。然后当代码执行到方法体中声明变量的位置,这里会根据变量为值类型还是引用类型,体现出差别。

第一种情况,变量为值类型。那么它将被进栈置栈顶,存放在栈上。当方法执行结束,结果被返回,此时该方法在栈上分配的所有空间都被清空,程序将自动回到栈上最初调用方法的位置。这就告诉我们,栈是由内存自行维护的,不存在垃圾收集的问题。

第二种情况,变量为引用类型。那么它将在堆上被创建,同时在栈上生成一个指向这个堆的指针。当方法执行结束后,栈上的相关内容被清空,此时在堆中将剩下孤零零的引用类型变量。这就产生了垃圾,需要靠垃圾回收机制来收回这部分空间。垃圾回收是非常消耗性能的,所以对于堆和栈的使用,我们需要特别注意。

 


战国工作室  供稿