struct必须显式加访问修饰符,嵌套时默认private;不可定义无参构造函数但可写带参构造且须初始化所有字段;赋值为深拷贝,修改副本不影响原值;只读场景应使用readonly struct。

struct 关键字必须显式加访问修饰符
不加 public 的 struct 在大多数场景下会直接编译失败——比如定义在命名空间顶层却没写修饰符,C# 默认按 internal 处理,但如果你在另一个程序集里引用它,就完全不可见。更隐蔽的问题是:在类内部嵌套 struct 时,若漏写 public 或 internal,它默认变成 private,连同属一个类的其他成员都访问不了。
- 总是显式写
public struct Point { ... },别依赖默认 - 嵌套 struct 要对外暴露,必须用
public;仅限本类使用可选private,但得想清楚是否真需要嵌套 - 字段也一样:不写
public就是private,p.X这种直接访问会报错
不能定义无参构造函数,但能写带参构造
C# 编译器强制为每个 struct 自动生成一个隐式无参构造函数,把所有字段设为默认值(0、null、false 等),你无法重写或删除它。一旦你写了任何带参构造函数,就必须确保它初始化所有字段,否则编译不过。
- 错误写法:
public Point() { }→ 编译错误 CS0568 - 正确写法:
public Point(int x, int y) { X = x; Y = y; },且必须赋值全部字段 - 字段自带默认值(C# 10+ 支持
public int X = 10;)不等于构造函数可以省略赋值——带参构造里仍要显式覆盖或确认
值语义导致的“假修改”陷阱
结构体赋值是深拷贝,不是引用传递。看起来你在改 p2,其实只是改了副本,原变量 p1 完全不受影响。这个特性在链式调用、集合遍历、方法传参时特别容易翻车。
Point p1 = new(1, 2); Point p2 = p1; p2.X = 99; Console.WriteLine(p1.X); // 输出 1,不是 99- 遍历
List时用foreach (var p in list),改p.X没用,因为p是副本 - 想安全修改集合中某项?得用索引:
list[0] = new Point(5, 5);或者用ref局部变量(C# 7.0+)
什么时候该用 readonly struct
如果你的结构体只读(比如坐标、颜色、时间戳),强烈建议声明成 readonly struct。它不只是语义提醒,而是编译器强制保护:所有实例字段自动变为只读,连属性的 set 都不允许(除非用 init),还能避免意外装箱和 JIT 优化障碍。
- 写法:
public readonly struct Size { public double Width { get; init; } public double Height { get; init; } } - 好处:防止误改状态、提升 CPU 缓存友好性、明确契约——调用方知道这东西不会变
- 注意:
readonly不等于不可变:如果字段是List这类引用类型,内容仍可变;真正不可变需配合ImmutableArray等类型
结构体看着简单,但值语义 + 隐式构造 + 字段可见性这三块叠在一起,最容易在跨方法、跨集合、跨程序集时悄悄出问题。别图省事跳过 public,也别以为“赋值=关联”,更别在没想清生命周期前就把大对象塞进 struct 里。










