十三:引用类型和值类型

引用类型(reference type)

     引用类型是从托管堆上分配的,C#的new操作符会返回对象的内存地址——也就是指向对象的内存地址,使用引用类型会对性能有一定的影响:

(1)内存必须从托管堆上分配

(2)堆一分配的每个对象都有一些额外的成员,而且这些成员必须初始化

(3)对象中的其它字节总是设为零

(4)从托管堆上分配一个对象,可能强制执行一次垃圾回收

值类型(value type)

     值类型的实例通常是在线程堆栈上分配的,在代表值类型的一个变量中,并不包含一个指向实例的指针,变量中包含了实例本身的字段,在对值类型的实例操作时,不需要提领一个指针,值类型的实例不受垃圾回收器的制约。值类型缓解了托管堆上的压力,并减少一个应用程序在其生存期内要进行垃圾回收的次数。

     任何称作“类”的类型都是引用类型,称为结构或者枚举的类型都是值类型。所有的结构都是从System.ValueType派生的,而System.ValueType又是从System.Object派生的,所有的枚举类型都是从System.Enum派生,而System.Enum又是从System.ValueType派生,所以可以说值类型是从System.ValueType派生。

以下代码和图演示了引用类型和值类型的区别:

//引用类型SomeRef

    class SomeRef

    {

        public Int32 x;

    }

    //值类型SomeVal

    struct SomeVal

    {

        public Int32 x;

    }

    static void ValueTypeDemo()

    {

        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 = 9;                  //只修改v1.x而不修改v2.x
        Console.WriteLine(r1.x);   //8        
        
Console.WriteLine(r2.x);   //8        
        
Console.WriteLine(v1.x);   //9
        Console.WriteLine(v2.x);   //5

    }

 

 

      

上面

SomeVal v1 = new SomeVal();//在堆栈上分配

也可以写成

SomeVal v1;//在堆栈上分配

     这一行生成的IL代码也公在线程堆栈上分配实例,并将字段初始化为0,但不使用new,C#编译器不会“认为”它已经初始化,使用它的字段时编译不通过。看以下代码,使用以上定义的两个类型:

        SomeVal v1;

        Console.WriteLine(v1.x);//编译不通过,使用了可能未赋值的字段x

        v1.x = 1;

        Console.WriteLine(v1.x);//输出1

        SomeRef r1;

        Console.WriteLine(r1.x);//编译不通过,使用了未赋值的局部变量r1


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

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

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

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

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

 

 

posted @ 2009-01-27 12:26  Done  阅读(857)  评论(3编辑  收藏  举报