C# 结构体和类的选择 C#什么时候应该用struct代替class

来源:这里教程网 时间:2026-02-21 17:40:59 作者:

结构体适合值语义且体积小的场景

当数据本质上是“值”而非“对象”,比如坐标点、颜色、时间跨度,且实例大小通常不超过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<t></t>
中会被复制多次;而
class
只传引用,更轻量
async
方法中捕获的局部
struct
变量可能被提升到状态机类中,失去值类型优势

常见误用:把“小”等同于“适合用 struct”

一个

struct
即使只有两个
int
,如果它常被装箱(例如放进
ArrayList
、作为
Dictionary<string object></string>
的 value、调用非泛型接口方法),性能反而比
class
差。.NET Core 2.1+ 的
Span<t></t>
ReadOnlySpan<t></t>
是特例——它们是 ref-like 类型,只能栈分配,但这不是普通
struct
的使用模式。

避免在泛型非约束上下文中把
struct
object
别为了“避免 new”而强行用
struct
new MyClass()
在现代 .NET 中堆分配开销极低
dotnet-counters
或 BenchmarkDotNet 验证实际分配行为,而不是凭直觉

一个快速判断 checklist

遇到新类型定义时,问自己这五条:

它的相等性是否应该基于字段逐个比较?→ 是,倾向
struct
是否需要把它当作“同一个东西”被多个地方修改?→ 是,必须用
class
是否会频繁作为参数传入非泛型方法(如
void Log(object o)
)?→ 是,避开
struct
是否包含引用类型字段(如
string
List<int></int>
)?→ 是,
struct
复制开销大,且易引发意外共享
是否要序列化为 JSON 或 ProtoBuf?→ 查目标库文档:有些对
struct
支持弱(如旧版 Newtonsoft.Json 默认忽略无参构造)

最常被忽略的一点:

struct
的默认构造函数永远存在且不可禁用,它会把所有字段设为 0 / null / default(T),哪怕你写了带参构造——这点和
class
的行为不一致,容易在初始化逻辑里埋坑。

相关推荐