public class Container
{
private MyType _a = new MyType();
private MyType _b = new MyType();
}
// MyType 為 struct(實值型別):
// 1 次堆積配置,大小 = 2 × sizeof(MyType)
// MyType 為 class(參考型別):
// 3 次堆積配置:
// - Container 物件(含 2 個參考,8 bytes × 2 = 16 bytes)
// - _a 物件
// - _b 物件
MyType[] arr = new MyType[100];
// 實值型別:1 次配置,連續記憶體,100 × sizeof(MyType)
// 參考型別:1 次配置參考陣列(100 × 8 bytes),所有元素為 null
// 需再 100 次配置實際物件 → 101 次配置、記憶體碎片、GC 壓力大
// 實值型別:資料容器,不可變最佳
public readonly struct Point3D
{
public double X { get; }
public double Y { get; }
public double Z { get; }
public Point3D(double x, double y, double z) => (X, Y, Z) = (x, y, z);
}
// 參考型別:行為實體,支援多型
public abstract class Shape
{
public abstract double Area { get; }
public virtual void Draw() { ... }
}
public class Circle : Shape
{
public double Radius { get; }
public override double Area => Math.PI * Radius * Radius;
}
// v1: struct
public struct Employee
{
public string Name;
public decimal Salary;
public void Pay(BankAccount a) => a.Deposit(Salary);
}
// v2: class(加入繼承)
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
public virtual void Pay(BankAccount a) => a.Deposit(Salary);
}
// 影響:
// - 指派語意從複製變為參考共享
// - null 成為合法值,需防禦性檢查
// - 等價比較從結構相等變為參考相等
// - 陣列/集合記憶體模型完全不同
// - 所有呼叫端需重新編譯(二進位不相容)
| 特徵 | 傾向 struct | 傾向 class |
|---|---|---|
| 主要用途 | 資料封裝 | 行為/服務 |
| 不可變 | 是 | 視情況 |
| 大小 | < 16 bytes | 任意 |
| 頻繁陣列/集合 | 是 | 否 |
| 需繼承/多型 | 否 | 是 |
| 需 null 語意 | 否 | 是 |
| 身分識別重要 | 否 | 是 |
| 高頻複製/傳遞 | 是 | 否 |
預設選擇 class。只有明確需要實值語意(複製、不可變、高效能陣列)且符合上表特徵時,才用 struct。 變更決定成本極高,設計階段務必審慎評估。