C#12、类和结构体的区别
·
在 C# 中,类(class) 和 结构体(struct) 都可以用来定义自定义类型,封装数据和行为,但它们在底层机制和使用场景上有本质区别。作为初级 C# 工程师,理解这些区别非常重要。
✅ 核心区别总结
| 特性 | 类(class) |
结构体(struct) |
|---|---|---|
| 类型类别 | 引用类型(Reference Type) | 值类型(Value Type) |
| 内存分配 | 分配在 堆(Heap) 上 | 通常分配在 栈(Stack) 上(或内联) |
| 赋值行为 | 复制引用(两个变量指向同一对象) | 复制整个值(两个独立副本) |
| 默认构造 | 可以有无参/有参构造函数 | 总是有一个隐式的无参构造函数(不能删除) |
| 继承 | 支持继承(单继承) | 不能继承其他 struct 或 class(但可实现接口) |
null 值 |
可以为 null |
不能为 null(除非用 Nullable<T>,如 int?) |
| 性能 | 涉及堆分配和垃圾回收(GC) | 无 GC 开销,适合高频小对象 |
| 适用场景 | 大型、复杂、有生命周期的对象 | 小型、简单、频繁创建的数据(如坐标、颜色) |
🔍 详细解释 + 示例
1. 引用类型 vs 值类型(最关键!)
类(引用类型):
class PointClass
{
public int X, Y;
public PointClass(int x, int y) { X = x; Y = y; }
}
var p1 = new PointClass(1, 2);
var p2 = p1; // p2 和 p1 指向同一个对象
p2.X = 10;
Console.WriteLine(p1.X); // 输出 10!因为 p1 和 p2 是同一个对象
结构体(值类型):
struct PointStruct
{
public int X, Y;
public PointStruct(int x, int y) { X = x; Y = y; }
}
var p1 = new PointStruct(1, 2);
var p2 = p1; // p2 是 p1 的完整副本
p2.X = 10;
Console.WriteLine(p1.X); // 输出 1!p1 不受影响
💡 关键记忆点:
- 类 → 共享数据(改一个,另一个也变)
- 结构体 → 独立副本(改一个,另一个不变)
2. 能否为 null?
PointClass c = null; // ✅ 合法
PointStruct s = null; // ❌ 编译错误!
// 但可以用可空类型:
PointStruct? s2 = null; // ✅ 合法(相当于 Nullable<PointStruct>)
3. 继承与多态
-
类:支持继承、虚方法、多态。
class Animal { public virtual void Speak() => Console.WriteLine("..."); } class Dog : Animal { public override void Speak() => Console.WriteLine("Woof!"); } -
结构体:不能继承其他 struct 或 class,但可以实现接口。
struct Point : IEquatable<Point> { public bool Equals(Point other) => X == other.X && Y == other.Y; }
⚠️ 所有 struct 都隐式继承自
System.ValueType,而ValueType继承自object,但这对开发者透明。
4. 构造函数限制
-
结构体不能有显式的无参构造函数(C# 10 之前),且字段不能在声明时初始化(除非是 const 或 static)。
struct BadStruct { public int X = 10; // ❌ C# 9 及之前不允许(C# 10+ 允许) public BadStruct() { } // ❌ 不能显式定义无参构造(C# 10+ 允许但有限制) } -
类没有这些限制。
💡 C# 10+ 放宽了 struct 的限制,但作为初学者,建议仍按传统方式使用。
5. 性能与使用建议
| 使用 struct 当…… | 使用 class 当…… |
|---|---|
数据小(≤ 16 字节,如 Point, Color) |
数据大或复杂 |
| 生命周期短、频繁创建(如循环中) | 需要继承或多态 |
行为像“值”(如 int, DateTime) |
行为像“对象”(如 Person, Order) |
不需要 null 语义 |
需要 null 表示“无” |
📌 .NET 官方建议:
“如果类型满足以下所有条件,考虑使用 struct:
- 逻辑上表示单个值(如
int)- 实例大小小于 16 字节
- 不可变(immutable)
- 不需要频繁装箱”
✅ 常见内置例子
| 类型 | 是 class 还是 struct? |
|---|---|
string |
class |
int, bool, double |
struct |
DateTime, Guid, TimeSpan |
struct |
List<T>, StringBuilder |
class |
Point (System.Drawing) |
struct |
💡 初学者一句话总结:
用
class表示“对象”,用struct表示“值”。
不确定时,优先用class;只有当你明确需要“值语义”且数据很小时,才用struct。
问题
结构体的基本类型是什么?
是System.ValueType
是否从结构体继承?
不,所有结构体都是密封的,因为所有值类型都是密封的。
做二维坐标系中,你会怎么表示一个点?
创建一个具有两个float只读属性x和y的结构体。
更多推荐
所有评论(0)