第11章 结构
11.1 什么是结构
结构是数据类型,与类相似,都有数据成员和函数成员,
重要的区别:
- 类是引用类型,结构是值类型。
- 结构是 隐式密封 的,不能派生。
c#
// point 结构
struct Point
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
Point first, second, third;
first.X = 10;
first.Y = 10;
second.X = 20;
second.Y = 20;
third.X = first.X + second.X;
third.Y = first.Y + second.Y;
Console.WriteLine($ "first: { first.X }, { first.Y }");
Console.WriteLine($ "second: { second.X }, { second.Y }");
Console.WriteLine($ "third: { third.X }, { third.Y }");
}
}
11.2 结构是值类型
结构类型变量含有自己的数据,
- 结构类型的变量不能为 null。
- 两个结构变量不能引用同一对象。
c#
class CSimple
{
public int X;
public int Y;
}
struct Simple
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
// 类的内存 在堆上
CSimple cs = new CSimple();
// 结构的内存 在栈上
Simple ss = new Simple();
// 。。。
}
}
11.3 对结构赋值
对结构赋值,就是将一个结构的值 复制给另一个结构。
类赋值后,cs2和cs1 指向堆中同一个对象,
结构赋值后,ss2成员的值和ss1相同
c#
class CSimple
{ public int X; public int Y; }
struct Simple
{ public int X; public int Y; }
class Program
{
static void Main()
{
// Class instances
CSimple cs1 = new CSimple(), cs2 = null;
// Struct instances
Simple ss1 = new Simple(), ss2 = new Simple();
cs1.X = ss1.X = 5;
cs1.Y = ss1.Y = 10;
// assign class/struct instance
cs2 = cs1;
ss2 = ss1;
}
}
11.4 构造函数和析构函数
结构可以有实例构造函数和静态构造函数,但没有析构函数。
11.4.1 实例构造函数
语言隐式地为每个结构提供一个无参数的构造函数,构造函数把每个成员设置为该类型的默认值。
值成员设置为默认值,引用成员设置为null。
每个结构都存在预定义的无参构造函数。在 C# 10 之前,不能删除或重定义。
在 C# 11 之前,结构类型的构造函数必须初始化该类型的所有实例字段。
可以创建其他的有参构造函数。
调用一个构造函数仍需要使用 new 调用构造函数。
c#
struct Simple
{
public int X;
public int Y;
// Constructor with parameters
public Simple(int a, int b)
{
X = a;
Y = b;
}
}
class Program
{
static void Main()
{
// Call implicit constructor
Simple s1 = new Simple();
Simple s2 = new Simple(5, 10);
Call constructor
Console.WriteLine($ "{ s1.X},{ s1.Y }");
Console.WriteLine($ "{ s2.X},{ s2.Y }");
}
}
也可以不使用 new 创建结构实例,但是有如下限制:
在设置数据成员的值后,才能使用该成员。
对所有数据成员赋值后,才能调用函数成员。
c#
struct Simple
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
// No constructor calls
Simple s1, s2;
// Compiler error,Not yet assigned
Console.WriteLine("{0},{1}", s1.X, s1.Y)
s2.X = 5;;
s2.Y = 10;
Console.WriteLine($ "{ s2.X},{ s2.Y }");
}
}
11.4.2 静态构造函数
与类相似,结构的静态构造函数 创建并初始化静态数据成员,不能引用实例成员。
遵从与类的静态构造函数一样的规则,但允许有不带参数的静态构造函数。
下面两种行为,任一种发生之前,会调用静态构造函数:
调用显示声明的构造函数
引用结构的静态成员。
11.4.3 构造函数和析构函数小结
类型 | 描述 |
---|---|
实例构造函数-无参数 | 不能在程序中声明,系统提供隐式的构造函数,无法被删除或重定义 |
实例构造函数-有参数 | 可以在程序中声明 |
静态构造函数 | 可以在程序中声明 |
析构函数 | 不能在程序中声明,不允许声明析构函数 |
11.5 属性和字段初始化语句
- 在 C# 10 之前,不允许使用实例属性和字段初始化语句。
- 结构体中的静态属性和静态字段,在声明结构体时可以进行初始化。
11.6 结构是密封的
结构是隐式密封的,不支持派生其他结构。
由于结构不支持继承,因此下面的修饰符不能用于结构:
-
protected
-
protected internal
-
abstract
-
sealed
-
virtual
结构本身派生自 System.ValueType(System.ValueType 派生自 object),可以使用 new 和 override 去覆盖或重定向 System.ValueType 中同名的成员。
11.7 装箱和拆箱
装箱:值类型 → 引用类型
拆箱:引用类型 → 值类型
11.8 结构作为返回值和参数
结构可以作为返回值和参数
- 将结构作为返回值或值参数时,均会创建副本。
- 使用 ref 或 out 参数时,将会传递结构的引用,可以修改其数据成员。
11.9 关于结构的更多内容
对结构进行分配的开销比类小,可以提高性能。
-
注意装箱和拆箱的高昂代价。
-
预定义简单类型尽管被视为原始类型,但在 .NET 中实现为结构。
- int、short、long 等
-
类似分部类,可以声明分部结构。
结构和类一样,可以实现接口。