Struct不是轻量版class,高频创建、集合存储或跨方法传参时性能可能比class差3倍以上;赋值即深拷贝,超16字节需警惕;不能继承但可实现接口,装箱会抵消性能优势。

Struct 不是“轻量版 class”,用错场景反而拖慢程序——尤其在高频创建、集合存储、跨方法传参时,性能可能比 class 差 3 倍以上。
Struct 赋值就是深拷贝,别当引用类型用
很多人以为 struct 只是“没继承的 class”,结果在循环里反复赋值大结构体,栈上疯狂复制几百字节数据。比如:
struct HeavyData {
public double X1, X2, X3, X4, X5;
public double Y1, Y2, Y3, Y4, Y5;
public byte[1024] Buffer; // 实际项目中真有这种字段
}这段代码看似无害,但每次执行 s2 = s1,就会复制 1024+8×10 = 1096 字节。而 class 同样逻辑只复制 8 字节(引用地址)。
- 栈空间有限,单个
struct超过 ~16 字节就该警惕 - 数组或
List<T>存储struct时,Add()触发拷贝;class则只是存引用 - 方法参数传
struct默认按值传递,加ref或in才避免拷贝(但语义变了)
Struct 构造函数必须初始化所有字段,且不能有无参构造(C# 10 前)
下面这段代码在 C# 9 及更早版本直接编译失败:
struct Point {
public int X;
public int Y;
public Point(int x) { X = x; } // ❌ 编译错误:Y 未赋值
// public Point() { } // ❌ 显式定义无参构造也不允许
}必须写成:
struct Point {
public int X;
public int Y;
public Point(int x, int y) {
X = x;
Y = y;
}
}- C# 10+ 允许显式无参构造,但必须手动初始化全部字段,且不能调用
this() - 字段声明时初始化(如
public int X = 1;)在 C# 10+ 才支持,旧项目会报错 - 不初始化字段 → 编译器强制你初始化,不是靠默认值“蒙混过关”
Struct 不能为 null,但 Nullable<T> 是语法糖,不是新类型
Point p = null; 永远编译不过。想表达“可能不存在”,得用:
Point? p = null; // 等价于 Nullable<Point>
这不是泛型包装那么简单:
-
p.Value访问前必须检查p.HasValue,否则运行时报InvalidOperationException -
Point?实际是struct套一层Nullable<T>,仍属值类型,栈上分配(除非装箱) - 传给接受
Point的方法时,p.Value会触发隐式拆箱;若p为null,直接炸
Class 支持虚方法和继承,Struct 不能,但能实现接口
想让类型参与多态?struct 只能走接口路线,且要注意装箱开销:
interface IShape { double Area(); }
struct Circle : IShape {
public double Radius;
public double Area() => Math.PI * Radius * Radius;
}
<p>IShape s = new Circle { Radius = 2.0 }; // ⚠️ 这里发生装箱!堆上分配</p>- 接口变量引用
struct实例 → 强制装箱 → 堆分配 + GC 压力 - 用
Span<T>或ref struct可规避,但失去通用性 - 需要继承树(如
Shape → Rectangle → RoundedRectangle)?只能选class
最常被忽略的一点:struct 的“高性能”只在它真的小、真的短命、真的不逃逸到堆上时才成立。一旦进了 object、ArrayList、Task<T> 或被接口变量持有,立刻装箱——那还不如一开始就用 class。



















