在 C# 中,结构体(struct) 是一种值类型数据类型,适用于封装小型数据组。与类(class)不同,结构体在栈(Stack)上分配内存,且赋值时会发生值复制。以下是结构体的核心特性和用法:
结构体核心特点
结构提供了一种轻量级的数据类型,适用于表示简单的数据结构,具有较好的性能特性和值语义:
- 值类型:赋值时复制整个数据,修改副本不影响原数据。
- 结构可带有方法、字段、索引、属性、运算符方法和事件,适用于表示轻量级数据的情况,如坐标、范围、日期、时间等。
- 结构可定义构造函数,但不能定义析构函数。但是,您不能为结构定义无参构造函数。无参构造函数(默认)是自动- 定义的,且不能被改变(C# 10 前不能定义无参构造器,所有字段需在构造器中初始化。)。
- 与类不同,结构不能继承其他的结构或类。
- 结构不能作为其他结构或类的基础结构。
- 结构可实现一个或多个接口。
- 结构成员不能指定为 abstract、virtual 或 protected。
- 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构可以不使用 New 操作符即可被实例化。
- 如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。
- 结构变量通常分配在栈上,这使得它们的创建和销毁速度更快。但是,如果将结构用作类的字段,且这个类是引用类型,那么结构将存储在堆上。
- 结构默认情况下是可变的,这意味着你可以修改它们的字段。但是,如果结构定义为只读,那么它的字段将是不可变的。
结构体 vs 类
特性 | 结构体(struct) | 类(class) |
---|---|---|
类型 | 值类型(栈内存) | 引用类型(堆内存) |
继承 | 不支持 | 支持 |
默认构造器 | C# 10 前无隐式无参构造器 | 有隐式无参构造器 |
赋值行为 | 复制值 | 复制引用 |
适用场景 | 小型、频繁创建的数据 | 复杂对象、需要继承的场景 |
结构体定义示例
public struct Point
{public int X;public int Y;// C# 10+ 允许显式无参构造器public Point(){X = 0;Y = 0;}public Point(int x, int y){X = x;Y = y;}public void Print() => Console.WriteLine($"({X}, {Y})");
}
使用结构体
// 创建结构体实例
Point p1 = new Point(10, 20);
Point p2 = p1; // 值复制p2.X = 30; // 修改副本不影响原数据
p1.Print(); // 输出: (10, 20)
p2.Print(); // 输出: (30, 20)// 使用无参构造器(C# 10+)
Point p3 = new Point();
p3.Print(); // 输出: (0, 0)
何时使用结构体?
- 数据量小:字段较少(通常少于 16 字节)。
- 不可变需求:设计为不可变类型(所有字段只读)。
- 避免装箱:减少值类型与引用类型转换的性能损耗。
- 高频实例化:如游戏中的坐标计算,减少堆内存压力。
注意事项
- 避免大型结构体:复制成本高,可能降低性能。
- 慎用可变结构体:修改副本可能导致预期外的行为。
- 构造器必须初始化所有字段:否则编译报错。
- 实现接口需谨慎:可能导致装箱操作(将结构体转为 object 或接口类型时)。
通过合理使用结构体,可以优化内存分配和程序性能,但需根据场景权衡值与引用类型的优缺点。