一、核心定性

  • class :引用类型
  • struct :值类型

二、栈分配还是堆分配

1. 结构体 struct(值类型)
  • 局部变量:直接分配在 栈 Stack
  • 作为类的字段:跟着对象一起分配在 堆 Heap(内嵌在对象内存里)
  • 作为数组元素:数组在堆,结构体内嵌在数组堆内存,不是单独堆对象
  • 永远不会单独在堆上新建对象,除非装箱

2. 类 class(引用类型)
  • 对象实例:永远分配在 堆 Heap
  • 引用变量:存地址,在 栈 Stack

一句话记

  • struct 本身优先站栈;被包裹(字段 / 数组)就嵌到堆里
  • class 实例永远堆上,引用永远栈上

装箱补充

struct 赋值给 object、接口、泛型引用类型参数 → 装箱:会在堆上创建一个包装对象,把结构体值拷贝进去,产生 GC 开销。

struct Point { public int X; }
object o = new Point(); // 装箱:栈结构体内嵌到堆包装对象

三、本质区别一览表

对比项 struct 结构体 class 类
类型分类 值类型 引用类型
内存位置 局部→栈;字段 / 数组→内嵌堆 实例永远堆,引用栈
赋值方式 值拷贝(复制一份全新数据) 引用拷贝(只复制地址,共用同一个对象)
继承 不能继承类,只能实现接口;隐式继承 ValueType 支持单类继承、多接口继承
构造函数 有无参默认构造,不能自定义无参构造 可自定义无参、有参构造
成员默认值 字段必须全部赋值才能用 引用默认 null,值类型默认 0
析构函数 不能写析构 可以写析构~ClassName ()
生命周期 栈上自动释放,无 GC;装箱才走 GC 全靠 GC 回收
可变性 建议设计成不可变 默认可变
初始化 可不用 new 直接用 必须 new 创建实例

四、赋值行为差异

struct 值拷贝

struct Point
{
    public int X;
}

Point p1 = new Point();
p1.X = 10;
Point p2 = p1; // 完整拷贝一份
p2.X = 20;

// 互不影响
Console.WriteLine(p1.X); // 10
Console.WriteLine(p2.X); // 20

class 引用拷贝

class Point
{
    public int X;
}

Point p1 = new Point();
p1.X = 10;
Point p2 = p1; // 只复制地址,指向同一个堆对象
p2.X = 20;

// 互相影响
Console.WriteLine(p1.X); // 20

五、什么时候用 struct?什么时候用 class?

用 struct 场景

  1. 数据量小(一般小于 16 字节)
  2. 单纯数据载体,无复杂行为
  3. 频繁创建、销毁,追求栈分配无 GC 开销
  4. 不需要继承

例:坐标、颜色、范围、配置小结构体

用 class 场景

  1. 数据量大、成员多
  2. 需要继承、多态
  3. 需要引用共享、修改同步
  4. 有复杂业务方法、生命周期管理

六、总结

  • struct 是值类型,class 是引用类型
  • struct 局部在栈,作为字段 / 数组内嵌到堆;class 实例永远堆,引用在栈
  • struct 赋值是值拷贝,各自独立;class 赋值是地址拷贝,共用对象
  • struct 不能继承类、无自定义无参构造;class 支持完整继承
  • 小数据、高频分配、追求无 GC 用 struct;复杂业务、继承多态用 class
  • struct 赋值给 object / 接口会装箱,逃逸到堆,产生 GC。

更多推荐