FROM P198
1.什么是结构
结构与类的区别:
□类是引用类型而结构是值类型
□结构是隐式密封的,这意味着它们不能被派生
2.结构是值类型
□结构类型的变量不能为null
□两个结构变量不能引用同一个对象
e.g.下图展示了该代码中的两个变量如何被安排在内存中
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace review 8 { 9 class CSimple 10 { 11 public int X; 12 public int Y; 13 } 14 struct Simple 15 { 16 public int X; 17 public int Y; 18 } 19 class Program 20 { 21 static void Main(string[] args) 22 { 23 CSimple cs = new CSimple(); 24 Simple ss = new Simple(); 25 Console.Read(); 26 } 27 } 28 }
3.对结构赋值
把一个结构赋值给另一个结构,就将一个结构的值复制给另一个结构。这和复制类变量不同,复制类变量时只复制引用。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace review 8 { 9 class CSimple 10 { 11 public int X; 12 public int Y; 13 } 14 struct Simple 15 { 16 public int X; 17 public int Y; 18 } 19 class Program 20 { 21 static void Main(string[] args) 22 { 23 CSimple cs1 = new CSimple(), cs2 = null; 24 Simple ss1 = new Simple(), ss2 = new Simple(); 25 cs1.X = ss1.X = 5; 26 cs1.Y = ss1.Y = 5; 27 cs2 = cs1; 28 ss2 = ss1; 29 Console.Read(); 30 } 31 } 32 }
4.构造函数和析构函数
结构可以有实例构造函数和静态构造函数,但不允许有析构函数。
4.1 实例构造函数
语言隐式地为每个结构提供一个无参数的构造函数。这个构造函数把结构的每个成员设置为该类型的默认值。值成员设置成它们的默认值,引用成员设置成null。
预定义的无参数构造函数对每个结构都存在,而且不能删除或重定义。但是,可以创建另外的构造函数,只要它们有参数。注意,这和类不同。对于类,编译器只在没有其他构造函数声明时提供隐式的无参数构造函数。
调用一个构造函数,包括隐式无参数构造函数,要使用new运算符。注意,即使不从堆中分配内存也要使用new运算符。
也可以不使用new运算符构建结构的实例。然而,如果这样做,有一些限制:
□在显示设置数据成员之后,才能使用它们的值
□在对所有数据成员赋值之后,才能调用任何函数成员
如下例所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace review 8 { 9 struct Simple 10 { 11 public int X; 12 public int Y; 13 } 14 class Program 15 { 16 static void Main(string[] args) 17 { 18 Simple s1, s2; 19 //Console.WriteLine("{0},{1}", s1.X, s1.Y);//编译错误 使用了可能未赋值的字段 20 s2.X = 5; 21 s2.Y = 10; 22 Console.WriteLine("{0},{1}", s2.X, s2.Y); 23 Console.Read(); 24 } 25 } 26 } 27 /* 28 * 输出如下: 29 * 5,10 30 * */
4.2 静态构造函数
与类相似,结构的静态构造函数创建并初始化静态数据成员,而且不能引用实例成员。结构的静态构造函数遵从与类的静态构造函数一样的规则。
以下两种行为,任意一种发生之前,将会调用静态构造函数。
□调用显式声明的构造函数
□引用结构的静态成员
如下例所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace review 8 { 9 struct Simple 10 { 11 public int X; 12 public int Y; 13 public static int t; 14 static Simple() 15 { 16 t = 6; 17 Console.WriteLine("static constructor used"); 18 } 19 } 20 class Program 21 { 22 static void Main(string[] args) 23 { 24 Simple s1, s2; 25 s2.X = 5; 26 s2.Y = 10; 27 Console.WriteLine("{0},{1}", s2.X, s2.Y); 28 Console.WriteLine("{0}", Simple.t); 29 Console.Read(); 30 } 31 } 32 } 33 /* 34 * 输出如下: 35 * 5,10 36 * static constructor used 37 * 6 38 * */
注意到,其中静态构造函数是在引用Simple.t前才调用。在此之前没有显式声明构造的s1、s2并没有导致静态构造函数的调用。
4.3构造函数和析构函数小结
5.字段初始化语句是不允许的!
如下所示
1 struct Simple 2 { 3 public int X=5; //编译错误:结构中不能实例属性或字段初始值设定项 4 public int Y=10; //编译错误:结构中不能实例属性或字段初始值设定项 5 }
6.结构是密封的
结构总是隐式密封的,因此,不能从它们派生出其他结构。
由于结构不支持继承,个别类修饰符用在结构成员上将没有意义。因此不能在结构成员声明时使用。不能用于结构的修饰符如下:
□protected
□internal
□abstract
□virtual
结构本身派生自System.ValueType,System.ValueType派生自object
两个可以用于结构成员并与继承相关的关键字是new和override修饰符,当创建一个和基类System.ValueType的成员有相同名称的成员时使用它们。所有结构都派生自System.ValueType
8.结构作为返回值和参数
□作为返回值或值参数时,都将创建其副本
□ref和out参数,传入方法便是引用,即可修改成员