C#中struct跟class的异同之处 - 实践

好的,这是 C# 中 struct(结构)和 class(类)的核心异同之处。理解它们的区别对于编写高效、正确的 C# 代码至关重要。

核心相同点

  1. 都是数据类型:都可以包含材料成员(字段、属性)和行为成员(方法、事件、索引器等)。

  2. 都支持接口:都可以实现一个或多个接口。


核心不同点(非常重要)

特性Struct (结构)Class (类)
类型值类型 (Value Type)引用类型 (Reference Type)
存储位置通常存储在栈(Stack)上<sup>*1</sup>。作为其他对象的成员时,内联存储在堆上。存储在托管堆(Managed Heap) 上。
内存分配分配和释放通常是快速、廉价的(栈操作)。分配在堆上,由垃圾回收器(GC)管理回收,有开销。
赋值操作复制整个值(创建一个完整的副本)。修改副本不影响原始值。复制引用(复制内存地址)。新旧变量指向同一个对象。修改一个会影响另一个。
继承隐式密封(sealed),不能从另一个结构或类继承。通过支持继承(单继承),能够从另一个类继承。
默认构造函数不能包含显式的无参构造函数。总是有一个隐式构造函数,将所有字段置为默认值(0, falsenull)。能够有无参构造函数。若是没有提供,也会有一个默认的。
字段初始化不能在声明时初始化实例字段可以在声明时初始化实例字段。
new 操作符new 关键字不是必须的(但推荐使用)。不使用 new 时,必须显式初始化所有字段后才能使用。必须使用new 关键字来创建实例(调用构造函数)。
this 的含义在实例方法中,this 是一个值变量(相当于 ref struct)。在实例方法中,this 是一个只读引用
是否可为 null不能直接为 null(除非是可空值类型 Nullable<T> 或 MyStruct?)。可以直接赋值为 null
性能考量适用于小体积、生命周期短的数据。大量赋值操作可能因复制而产生开销。适用于大对象、复杂的对象模型。赋值开销小(只复制引用)。

<sup>*1</sup> 关于“栈存储”的重要说明:这是一个常见的简化说法,有助于理解,但并不完全准确。更精确的说法是:结构变量的内存取决于其声明上下文。局部变量和方法参数确实在栈上,但如果结构是另一个类或堆上对象的字段,那么它就会内联存储在那个对象所在的堆上。


代码示例:说明赋值差异

// 定义一个类
public class PointClass
{
public int X { get; set; }
public int Y { get; set; }
}
// 定义一个结构
public struct PointStruct
{
public int X { get; set; }
public int Y { get; set; }
}
class Program
{
static void Main()
{
Console.WriteLine("--- Class ---");
PointClass p1 = new PointClass { X = 10, Y = 20 };
PointClass p2 = p1; // 复制的是引用(内存地址)
p2.X = 100;
Console.WriteLine($"p1.X: {p1.X}"); // 输出 100,因为 p1 和 p2 指向同一个对象
Console.WriteLine("--- Struct ---");
PointStruct s1 = new PointStruct { X = 10, Y = 20 };
PointStruct s2 = s1; // 复制的是整个值(创建一个全新的副本)
s2.X = 100;
Console.WriteLine($"s1.X: {s1.X}"); // 输出 10,s1 和 s2 是两个独立的副本
}
}

如何选择:何时用 Struct?何时用 Class?

使用 struct 的场景(遵循以下所有或大部分原则):
  1. 表示轻量级的数据结构,例如坐标点 (Point)、复数、RGB 颜色等。

  2. 逻辑上表示一个单一的值,其行为类似于内置类型(intdouble),例如 DateTimeDecimal

  3. 实例大小很小(通常建议在16 字节以下)。

  4. 是不可变的(Immutable),创建后状态就不会改变。这是强烈推荐的做法,可以避免很多值复制带来的困惑。

  5. 不需要频繁地进行装箱执行(将值类型转换为 object 引用)。

使用 class 的场景:
  1. 表示需要标识(Identity)的实体,例如“用户”、“订单”、“产品”。两个对象即使所有数据都相同,它们也是不同的对象。

  2. 需要继承和多态

  3. 对象较大或逻辑复杂

  4. 需要为 null 来表示语义上的“无”

简单总结:
class 是“可以做的事情”的抽象,而 struct 是“数据”的抽象。绝大多数情况下,你应该优先选择 class。只有在满足上述 struct 的使用场景时,才考虑使用它来优化性能。

posted @ 2025-09-03 18:49  yfceshi  阅读(9)  评论(0)    收藏  举报