实例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成员。