C# 2012程序设计实践教程 (清华电脑学堂)
上QQ阅读APP看书,第一时间看更新

4.1 结构

结构是一种值类型,通常用来封装小型相关变量组。例如,矩形的坐标或者库存商品的特征。本节将介绍与结构有关的内容,包括结构的定义、结构的成员和如何使用等。

4.1.1 定义结构

C#中的类是引用类型,而结构是值类型。C#中定义结构需要用struct关键字。定义语法如下:

    [struct-modifiers] struct identifier [struct-interfaces]{
        struct-body;
     }

其中,struct-modifiers是一个可选参数,表示结构可用修饰符,例如public、internal和private等,默认值为public。identifier表示结构的名称。struct-interfaces是可选参数,表示结构的基接口。struct-body表示结构体,即结构的内容。

提示

一般情况下,很少使用结构,而且很多人都不建议使用结构。但是它作为.NET Framework的一部分,还是有必要了解一下的。

【范例1】

创建名称为Book的结构,该结构包含三个成员,代码如下。

    public struct Book
    {
        public decimal price;
        public string title;
        public string author;
    }

4.1.2 结构成员

结构的成员和类很相似,可包含构造函数、常量、字段、属性、方法、事件、索引器、运算符和嵌套类型等。

(1)常量:用来表示常量的值。

(2)字段:结构中声明的变量。

(3)属性:用于访问对象或结构的特性的成员。

(4)方法:包含一系列语句的代码块,通过这些代码块能够实现预先定义的计算或操作。

(5)事件:一种使对象或结构能够提供通知的成员。

(6)索引器:又被称为含参属性,是一种含有参数的属性。提供以索引的方式访问对象。

(7)运算符:通过表达式运算符可以对该结构的实例进行运算。

(8)构造函数:包括静态构造函数和实例构造函数,静态构造函数使用static修饰;实例构造函数不必使用static修饰符。

注意

在结构中,如果同时需要上述几种成员,那么可以考虑使用类作为类型,而不再是结构。

开发者为结构显式定义无参构造函数是错误的,在结构体中初始化实例字段也是错误的。只能通过两种方式初始化结构成员:一是使用参数化构造函数;二是在声明结构后分别访问成员。对于任何私有成员或以其他方式设置为不可访问的成员,只能在构造函数中进行初始化。

如果使用new关键字创建结构对象,则会创建该结构对象,并调用适当的构造函数。与类不同,结构的实例化可以不使用new关键字,在这种情况下不存在构造函数调用,因此可以提高分配效率。但是,在初始化所有的字段之前,字段将保持未赋值状态且对象不可用。

当结构包含引用类型作为成员时,必须显式调用该成员的默认构造函数,否则该成员将保持未赋值状态且结构不可用。

【范例2】

本范例演示使用默认构造函数和参数化构造函数的struct初始化。实现步骤如下。

(1)创建名称是CoOrds的结构,在该结构中定义两个字段x和y,并在有参数的构造函数中对x和y初始化,代码如下。

     public struct CoOrds
     {
         public int x, y;
         public CoOrds(int p1, int p2) {
             x = p1;
             y = p2;
         }
     }

(2)向Main()方法中添加代码,首先分别实例化结构的无参和有参的构造函数,然后分别输出两个字段的值,代码如下。

     static void Main(string[] args)
      {
          CoOrds coords1 = new CoOrds();
          CoOrds coords2 = new CoOrds(10, 10);
          Console.Write("CoOrds 1:");
          Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
          Console.Write("CoOrds 2:");
          Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y);
          Console.ReadLine();
      }

(3)运行上述代码查看输出结果,内容如下。

    CoOrds 1:x = 0, y = 0
    CoOrds 2:x = 10, y = 10

【范例3】

本范例说明结构特有的功能,即结构在不使用new的情况下创建CoOrds对象。实现步骤如下。

(1)创建名称是CoOrds的结构,在该结构中声明两个字段x和y,在有参的构造函数中为两个字段赋值。

(2)向Main()方法中添加代码,首先声明CoOrds的结构对象,然后分别为该对象的x和y赋值,最后通过“对象名.字段”输出字段的值,代码如下。

    static void Main(string[] args)
     {
        CoOrds coords1;
        coords1.x = 10;
        coords1.y = 20;
        Console.Write("CoOrds 1:");
        Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
     }

(3)运行上述代码查看输出结果,内容如下。

    CoOrds 1:x = 10, y = 20

4.1.3 结构和类

结构与类共享大多数相同的语法,例如它们都可以实现接口、都拥有相同的成员、成员都有各自的存取范围和都可以声明和触发事件等。对于它们的不同点,表4-1分别从类型、分配空间、结构成员、构造函数、析构函数、初始化变量和基类等方面进行说明。

表4-1 结构和类的主要区别

结构和类各有各的优势,那么何时使用结构,何时使用类呢?下面根据不同的情况进行说明。

(1)堆栈的空间有限,对于大量的逻辑对象,创建类要比创建结构好一些。

(2)大多数情况下该类型只是一些数据时,结构是最佳的选择,否则使用类。

(3)在表现抽象或者多层次的数据时,类是最好的选择。

(4)如果该类型不继承自任何类型时使用结构,否则使用类。

(5)该类型的实例不会被频繁地用于集合中时使用结构,否则使用类。