C#程序设计经典300例
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

实例008 修改圆柱体的高度和底面半径——引用类型

【实例描述】

本实例主要介绍引用类型的赋值操作,以及引用类型赋值与值类型赋值的区别。实例中定义了一个圆形类和一个圆柱体结构体。在圆柱体结构体中声明了一个圆形类变量表示圆柱体底面,还声明了一个整型变量表示圆柱体的高度。实例通过修改圆柱体对象和圆形对象的成员变量值,说明引用类型和值类型在赋值时的区别。效果如图2-5所示。

图2-5 修改圆柱体对象的成员变量值和圆形对象的成员变量值

【实现过程】

(1)创建一个名为Reference的控制台应用程序,定义圆柱体结构体和圆形类,代码如下:

    //定义一个圆柱体结构体
    struct Column
    {
        public Circle Circle;                            //底面圆形
        public int Height;                               //圆柱体高度
    }
    //定义一个圆形类
    class Circle
    {
        public int Radius;                               //半径
    }

(2)在main函数中创建名为column1的圆柱体对象和名为circle1的圆形对象,并对其成员进行赋值,代码如下:

    Column column1 = new Column();                          //创建圆柱体1
    Circle circle1 = new Circle();                          //创建圆形1
    column1.Height = 20;                                    //设置圆柱体1的高度
    column1.Circle = circle1;                           //将圆形1赋值给圆柱体1底面圆形
    circle1.Radius = 10;                                    //设置圆形1半径
    Console.WriteLine("圆柱体1高度:{0}", column1.Height);    //输出圆柱体1的高度
    Console.WriteLine("圆柱体1底面半径:{0}", column1.Circle.Radius); //输出圆柱体1底面半径
    Console.WriteLine("将圆柱体1赋值给圆柱体2");

(3)定义一个名为column2的圆柱体对象并对其进行赋值,然后修改circle1和column2的成员变量值,代码如下:

    Column column2 = column1;                               //将圆柱体1赋值给圆柱体2
    Console.WriteLine("将圆形1半径改为30");
    circle1.Radius = 30;                                    //修改圆形1的半径
    Console.WriteLine("圆柱体1底面半径:{0}", column1.Circle.Radius); //输出圆柱体1底面半径
    Console.WriteLine("圆柱体2底面半径:{0}", column2.Circle.Radius); //输出圆柱体2底面半径
    Console.WriteLine("圆柱体1高度:{0}", column1.Height);    //输出圆柱体1的高度
    Console.WriteLine("圆柱体2高度:{0}", column2.Height);    //输出圆柱体2的高度
    Console.WriteLine("将圆柱体2高度改为40");
    column2.Height = 40;                                    //修改圆柱体2的高度
    Console.WriteLine("圆柱体1高度:{0}", column1.Height);    //输出圆柱体1的高度
    Console.WriteLine("圆柱体2高度:{0}", column2.Height);    //输出圆柱体2的高度

【代码解析】

实例代码中,首先定义了一个结构体类型Column 和类类型Circle,类类型是引用类型的一种,C#还提供了object对象类型、array数组类型、string字符串类型等引用类型供开发者使用。

注意:在C#中所有的引用类型均继承自object类型。有关类的具体用法,将在后面的章节中讲解。

说明:下面分析一下引用类型和值类型在内存中的分配。系统为C#程序在内存中分配了堆栈(stack)和托管堆(heap),堆栈用来存储值类型,而托管堆用来存储引用类型,该托管堆由垃圾收集器(Garbage Collector,GC)进行自动管理。

当创建一个值类型时,系统会直接在堆栈上为该值类型分配空间,而创建一个引用类型时,系统先在堆栈上为该引用分配内存,这个内存表示的是一个内存地址,然后在托管堆上为该引用对象的实例分配内存,将引用地址指向托管堆上分配的内存地址,这种分配方式不会受堆栈大小的限制,那么在引用传递的时候,其实是将堆栈中引用的地址传递给了另外一个引用,它们都指向托管堆中的同一个对象。引用对象的建立过程比较复杂,因此,性能也有所降低。值类型在其生命周期结束时,系统会自动将其从堆栈中删除,而引用对象会长时间保留在托管堆中,直到该引用对象不被任何一个变量所引用,垃圾收集器会在适当的时候将其回收。当然,用户可以调用 GC类的Collect方法对托管堆内存进行强制回收。

在Column结构中声明了一个Circle类型变量和一个int类型变量。这里要注意的是,Column结构属于值类型,而 Circle 类型属于引用类型。实例代码中创建了一个 Column 对象 column1和Circle对象circle1,将circle1对象赋值给column1的Circle成员变量,这个过程是将circle1的引用传递给 column1的 Circle。后面对 circle1 的 Radius 成员变量的修改会导致 column1 的Circle变量的Radius成员值发生改变。

实例代码中,将column1赋值给Column类型的column2,这个过程是值传递,将column1的一个副本传递给了column2,在复制的过程中,column1的Circle成员变量同样被复制了,但复制的是引用。因此,在对circle1的Radius成员值进行修改时会影响到column1、column2和Circle成员。但对column2的Height成员进行修改时并不会影响到column1的Height成员的值,因为在column2被赋值的时候,将column1的Height成员值赋值给了column2的Height成员。