c# class 和 struct 的区别

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

选 class 还是 struct?核心就看三点:要不要共享状态、会不会频繁复制、需不需要继承或虚方法。其他都是衍生影响。

赋值和传参时行为完全不同

这是最常踩坑的地方——你以为改的是副本,结果改了别人的数据,或者反过来。

class
赋值或传参时只拷贝引用地址,
c2 = c1
c1
c2
指向同一块堆内存
struct
赋值或传参时默认拷贝整个值(浅拷贝),
s2 = s1
后修改
s2.X
不会影响
s1.X
⚠️ 注意:如果
struct
里包含
string
class
字段,拷贝的只是那个引用,不是深层对象——这叫“值语义 + 引用字段”,容易误判为深拷贝
struct Point { public int X; public int Y; public string Tag; }
class Entity { public int Id; public string Name; }
<p>var p1 = new Point { X = 1, Y = 2, Tag = "A" };
var p2 = p1;
p2.X = 99;
p2.Tag = "B"; // ✅ p1.Tag 仍是 "A" —— string 是不可变引用,赋新值不改变原引用</p><p>var e1 = new Entity { Id = 1, Name = "Alice" };
var e2 = e1;
e2.Name = "Bob"; // ✅ e1.Name 也变成 "Bob"</p>

构造函数和初始化规则差异很大

struct 的构造函数不是“可选功能”,而是强制约束:你写的每个构造函数都必须显式初始化所有字段。

class
可以只写带参构造,也能用无参
new MyClass()
(编译器自动补默认构造)
struct
不能定义无参构造函数(C# 10+ 允许但仅限于
init
成员场景,日常仍应避免)
struct
总有隐式无参构造:直接声明
Point p;
就能用,
p.X
自动是
0
❌ 下面代码会编译失败:
struct BadPoint { public int X; public BadPoint(int y) { /* 忘了赋 X */ } }

什么时候该用 struct?别凭感觉,看这 3 个硬指标

不是“小就用 struct”,而是满足全部三条才考虑:

逻辑上是“纯数据载体”,比如
Vector3
Color
DateOnly
,不封装行为或状态机
大小稳定且 ≤ 16 字节(.NET 推荐阈值),避免栈溢出或复制开销过大 设计为不可变(
readonly struct
)或极少修改——因为每次赋值都在复制,改得勤反而更慢
✅ 推荐场景:
Span<t></t>
内部字段、DTO 中的坐标/金额/时间戳结构体、数学库中的向量/矩阵
❌ 禁止场景:含
event
virtual
方法、大数组字段、需要
IDisposable
的类型

最容易被忽略的一点:struct 在 class 字段里、数组里、async 状态机里,其实都分配在堆上——“struct 在栈上”只是局部变量的常见情况,不是铁律。性能优化前,先用

dotnet-counters
PerfView
看真实分配行为,别靠直觉猜。

相关推荐