博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C#中的数据类型

Posted on 2012-09-11 23:54  阳光梧桐  阅读(409)  评论(0)    收藏  举报

  C#中的数据类型归根结底可以分为两种类型:值类型(Value Type) 和 引用类型(Reference Type)

  划分的依据是他们在内存中的存储方式。值类型直接存储其值,数据存储在堆栈(stack)中;引用类型存储对值的引用,数据存储在堆(heap)中。

  堆栈(stack)是一种后进先出的数据结构,在内存中,值类型会被分配在栈上进行操作。堆(heap)是用于为类型实例(对象)分配空间的内存区域,在堆上创建一个对象,会将对象的地址传给堆栈上的变量(反过来叫变量指向此对象,或者变量引用此对象),用来定位该对象实例在heap中的位置,便于找到该对象实例。

  1.值类型

  值类型包括:枚举类型(Enum Type)和结构类型(Struct Type)两大类。需要特别说明的是基本数据类型(如:int、long、double等)实际上是FCL(框架类库)的别名,例如声明一个int类型,实际上是声明一个 System.Int32 的结构类型。

  所有的值类型都隐式的继承自 System.ValueType 类型(System.ValueType 本身是一个类类型,类类型属于引用类型),所有的引用类型都继承自 System.Object 基类,你不能显式地让结构继承一个类,因为C#不支持多重继承,而结构已经隐式继承自 System.ValueType。

  当声明一个值类型的变量(Variable)的时候,变量本身包含了值类型的全部字段,该变量会被分配在线程堆栈(Thread Stack)上。

  例如我们有这样一个值类型,代表了一个点的坐标:

    public struct ValPoint
    {
        public ValPoint(int x,int y)
        {
            this.x = x;
            this.y = y;
        }
        public int x;
        public int y;
    }

  当我们在程序中写下面这条语句时:

  ValPoint valPoint;

  实际产生的效果是声明了valPoint变量,变量本身包含了值类型的所有字段(即你想要的所有数据)。

  

  因为变量已经包含了值类型的所有字段,所以,此时你已经可以对它进行操作了(对变量进行操作,实际上是一系列的入栈、出栈操作)。

  valPoint.x=2;

  valPoint.y=3;

  Console.WriteLine("x={0},y={1}",valPoint.x,valPoint.y);  //输出x=2,y=3

  编译器隐式地会为结构类型创建无参数构造函数。在这个构造函数中会对结构成员进行初始化,所有的值类型成员被赋予0或相当于0的值(针对Char类型),所有的引用类型被赋予null值。(因此,Struct类型不可以自行声明无参数的构造函数)。所以,我们可以通过隐式声明的构造函数去创建一个ValPoint类型变量:

  ValPoint valPoint = new ValPoint();

  Console.WriteLine("x={0},y={1}",valPoint.x,valPoint.y);  //输出x=0,y=0 

  2.引用类型 

  引用类型包括:数组(Array)、类(Class)、接口(Interface)和委托(Delegate)。需要特别说明的是 string 类型实际上也是FCL(框架类库)的别名,声明一个 string 类型,实际上是声明一个 System.String 的类类型。

  System.String strName = "zhangsan";

  当声明一个引用类型变量的时候,该引用类型的变量会被分配到堆栈上,这个变量将用于保存位于堆上的该引用类型的实例的内存地址,变量本身不包含对象的数据。此时,如果仅仅声明这样一个变量,由于在堆上还没有创建类型的实例,因此,变量值为null,意思是不指向任何类型实例(堆上的对象)。对于变量的类型声明,用于限制此变量可以保存的类型。

  例如我们有这样一个类,代表了一个点的坐标:

    public class RefPoint
    {
        public RefPoint() : this(0, 0) { }
        public RefPoint(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }

        private int x;
        public int X
        {
            get { return x; }
            set { x = value; }
        }
        private int y;
        public int Y
        {
            get { return x; }
            set { x = value; }
        }
    }

  当我们仅写下面一声明条语句时,  

  RefPoint refPoint;

  它的效果如下图所示,仅仅在堆栈上创建一个不包含任何数据,也不指向任何对象(不包含创建在堆上的对象的地址)的变量。 

  

  而当我们使用new操作符时:

  RefPoint refPoint = new RefPoint();

  会发生这样的事:

  (1)在应用程序堆(Heap)上创建一个引用类型的实例(Instance)或者叫对象(Object),并为它分配内存地址。

  (2)自动传递该实例的引用给构造函数。(正因为如此,你才可以在构造函数中使用this来访问这个实例。)

  (3)调用该类型的构造函数。

  (4)返回该实例的引用(内存地址),赋值给refPoint变量。