struct适合值语义、体积小(≤16字节)、不可变的小型数据类型,如坐标点、颜色;class适合需引用语义、多态、生命周期管理或较大实例的场景。

结构体适合值语义且体积小的场景
当数据本质上是“值”而非“对象”,比如坐标点、颜色、时间跨度,且实例大小通常不超过16字节时,struct更合适。它在栈上分配(多数情况),避免堆分配和GC压力,访问局部性好。但要注意:.NET对struct有隐式装箱成本,一旦传给object或接口类型就会触发,反而更慢。
- 推荐尺寸:字段总大小 ≤ 16 字节(如
int x, y;或float r,g,b,a;) - 必须是不可变或显式控制可变性的设计(避免意外副本导致逻辑错乱)
- 不要继承、不能有无参构造函数(编译器强制)、不能有析构函数
- 泛型约束中可用
where T : struct限定只接受值类型
类更适合需要引用语义或复杂行为的类型
class 是默认选择,尤其当你需要多态、生命周期管理、事件、属性通知(INotifyPropertyChanged)、依赖注入容器托管,或者实例可能很大(如缓存数据块、树节点)时。struct无法被继承,也不能安全地实现 IDisposable(因为复制后资源归属不明确)。
- 有状态的业务实体(如
Order、User)几乎总是class - 需要虚方法、抽象基类、接口实现(尤其是带状态的)应选
class - 集合元素如果是
struct,在List中会被复制多次;而class只传引用,更轻量 -
async方法中捕获的局部struct变量可能被提升到状态机类中,失去值类型优势
常见误用:把“小”等同于“适合用 struct”
一个 struct 即使只有两个 int,如果它常被装箱(例如放进 ArrayList、作为 Dictionary 的 value、调用非泛型接口方法),性能反而比 class 差。.NET Core 2.1+ 的 Span 和 ReadOnlySpan 是特例——它们是 ref-like 类型,只能栈分配,但这不是普通 struct 的使用模式。
- 避免在泛型非约束上下文中把
struct当object用 - 别为了“避免 new”而强行用
struct;new MyClass()在现代 .NET 中堆分配开销极低 - 用
dotnet-counters或 BenchmarkDotNet 验证实际分配行为,而不是凭直觉
一个快速判断 checklist
遇到新类型定义时,问自己这五条:
- 它的相等性是否应该基于字段逐个比较?→ 是,倾向
struct - 是否需要把它当作“同一个东西”被多个地方修改?→ 是,必须用
class - 是否会频繁作为参数传入非泛型方法(如
void Log(object o))?→ 是,避开struct - 是否包含引用类型字段(如
string、List)?→ 是,struct复制开销大,且易引发意外共享 - 是否要序列化为 JSON 或 ProtoBuf?→ 查目标库文档:有些对
struct支持弱(如旧版 Newtonsoft.Json 默认忽略无参构造)
最常被忽略的一点:struct 的默认构造函数永远存在且不可禁用,它会把所有字段设为 0 / null / default(T),哪怕你写了带参构造——这点和 class 的行为不一致,容易在初始化逻辑里埋坑。










