C#学习笔记——结构与类

来源:互联网 发布:天敏网络机顶盒 编辑:程序博客网 时间:2024/06/02 07:33


1. 值类型和引用类型

在C#中有大量的值类型, int,char,float…等C#的预定义的基本类型都是值类型,这里面string是一个例外。值类型直接包含值,变量引用的位置就是值在内存中实际存储的位置,存储在称为栈的内存区域内。引用类型和引用它们的变量指向数据存储位置。引用类型并不直接存储值,它们存储的是对一个内存位置的引用(内存地址),要去那个位置才能找到真正的数据。引用类型指向的内存区域称为堆。

我们需要使用自定义的类型时,自定义的引用类型很常用,就是我们常用的“类”。在这里要提一下自定义的值类型,一种是“结构”,另外一种是“枚举”。•    C++中的结构是多余的东西,仅仅为了兼容C而存在。C#中的结构与类有许多实质的区别,结构是轻量级的自定义数据类型,其数据存储于栈中。

2. 结构和类的区别

比较项目

struct

class

1.         存储位置

托管堆

2.         变量赋值为null

不能

可以

3.         继承与派生

不支持

支持

4.         定义无参构造函数

不能

5.         构造函数初始化所有字段

必须

不必

6.         用new来实例化一个对象

不一定

必须

7.         定义析构函数

不能

8.         对象复制

正本与副本无关

浅拷贝和深拷贝

9.         如何回收

无需回收

自动回收机制

10.     参数传送

按值传送

按地址传送

11.     使用初始化表

不能

可以

12.     作为List元素能否修改

不能

可以

C++中,结构和类几乎是同义词,区别只在于:结构的成员默认为公开的,类的成员默认为私有的。但是在C#中,结构和类的成员默认都是私有的。

下面用一个代码实例说明一下上述区别的表现,代码选自《C#本质论4.0》,代码清单8-1:

using System;using System.Diagnostics;using System.ComponentModel;using System.Text;using System.Collections.Generic;namespace MyProcessSample{    struct Angle    {        //4.结构不能定义无参构造函数,所以以下的定义是错误的        //public Angle() { }//Error        //5.构造函数初始化所有字段,如下面的初始化必须包括全部三个字段        public Angle(int hours, int minutes, int seconds)        {            _Hours = hours;            _Minutes = minutes;            _Seconds = seconds;        }        public int Hours        {            get { return _Hours; }        }        public int _Hours;        public int Minutes        {            get { return _Minutes; }        }        private int _Minutes;        public int Seconds        {            get { return _Seconds; }        }        private int _Seconds;        public Angle Move(int hours, int minutes, int seconds)        {            return new Angle(                Hours + hours,                Minutes + minutes,                Seconds + seconds);        }    }    // Declaring a class - a reference type    // (declaring it as a struct would create a value type    // larger than 16 bytes.)    class Coordinate    {        //4.定义无参构造函数在类中是允许的,如下        public Coordinate() { }        public Angle Longitude        {            get { return _Longitude; }            set { _Longitude = value; }        }        private Angle _Longitude;        public Angle Latitude        {            get { return _Latitude; }            set { _Latitude = value; }        }        private Angle _Latitude;    }    class MyProcess    {        static void Main(string[] args)        {            //4.定义无参构造函数,在这里可以调用无参的构造函数,而且下面的输出为0,为什么??            Angle ag = new Angle();            Console.WriteLine(ag.Minutes);            //2.变量赋值为null 如下的代码说明struct不能直接赋值为null            //ag = null;//Error            //而可以使用下面的方式来声明            Angle? agg = null;            if (agg.HasValue)                Console.WriteLine("Has value");            else                Console.WriteLine("=NULL");            //6.用new来实例化一个对象             //struct可以不使用new来初始化,如ag3,并且可以对公有成员初始化,当然这样会引起数据的不安全            Angle ag2 = new Angle(10, 5, 2);            Angle ag3;            ag3._Hours = 9;            //class不可以,如cd2这样的形式初始化就会报错            Coordinate cd1 = new Coordinate();            cd1.Longitude = ag2;            Coordinate cd2;            //cd2.Longitude = ag2;//Error            Coordinate cd3 = new Coordinate { Latitude = ag2, Longitude = ag };            Angle ag4 = new Angle { _Hours = 5 };//这里说明struct也是可以使用初始化列表的,前提是这个字段是公有的            Angle ag5 = new Angle(7, 3, 1);            Angle ag6 = new Angle(9, 9, 9);            List<Angle> allAgs = new List<Angle>() { ag, ag2, ag4 };            Console.WriteLine(allAgs[0].Hours + "," + allAgs[1].Hours + "," + allAgs[2].Hours);            allAgs[0] = allAgs[1];            Console.WriteLine(allAgs[0].Hours + "," + allAgs[1].Hours + "," + allAgs[2].Hours);            allAgs[0] = ag5;            Console.WriteLine(allAgs[0].Hours + "," + allAgs[1].Hours + "," + allAgs[2].Hours);            Coordinate cd5 = new Coordinate { Latitude = ag5,Longitude=ag6 };            List<Coordinate> allCds = new List<Coordinate>() { cd1, cd3 };            Console.WriteLine(allCds[0].Latitude.Minutes + "," + allCds[1].Latitude.Minutes);            allCds[0] = allCds[1];            Console.WriteLine(allCds[0].Latitude.Minutes + "," + allCds[1].Latitude.Minutes);            allCds[0] = cd5;            Console.WriteLine(allCds[0].Latitude.Minutes + "," + allCds[1].Latitude.Minutes);            //以下说明引用类型的赋值存在深拷贝,浅拷贝的问题,直接赋值相当于浅拷贝            Coordinate cd6 = cd5;            Console.WriteLine(cd6.Longitude.Hours + "," + cd5.Longitude.Hours);            cd6.Longitude = new Angle(999, 999, 999);            Console.WriteLine(cd6.Longitude.Hours + "," + cd5.Longitude.Hours);        }    }}
对第8条,对象的复制方式,struct的形式完全和常用值类型一样,但是class的复制就涉及到深拷贝和浅拷贝,可具体参考本站其它博文(http://blog.csdn.net/shaopengfei/article/details/39376441)。

第11条,第12条来自陈老师的讲课资料,不过现在验证来好象有点出入,比如第11条,如果struct里有一个公有的字段,那么是可以使用初始化列表初始化的。第12条也是,当时陈老师是这么讲解的:

List<T>中,元素只能用索引器来获取,例如 a[i]。索引器返回的本是可读可写的元素,但struct元素是按值传送的,修改返回值对于List中的元素毫无影响。例如,a[i] = a[j];     C#此时发出编译错误,实在是提醒程序员别误入陷阱。但元素如果是class的,返回值则是按地址传送的,是一个引用,修改其值就是修改List中的元素, a[i] = a[j];  是允许的。

经过验证,见上述代码的第109-122行,这些都是可以实现的。或者我对这一段理解有问题,还有待于深入的探讨。

3. 结构适合的场合

struct 类型适于表示 Point、Rectangle 和 Color 等轻量对象。 尽管使用自动实现的属性将一个点表示为类同样方便,但在某些情况下使用结构更加有效。 例如,如果声明一个 1000 个 Point 对象组成的数组,为了引用每个对象,则需分配更多内存;这种情况下,使用结构可以节约资源。 因为 .NET Framework 包含一个名为 Point 的对象,所以本示例中的结构命名为“CoOrds”。

public struct CoOrds{    public int x, y;    public CoOrds(int p1, int p2)    {        x = p1;        y = p2;    }}
将较小的类声明为结构,可以提高系统的处理效率。



0 0
原创粉丝点击