struct(實值型別)還是 class(參考型別)?這是設計伊始必須決定、後期極難變更的抉擇。C++ 全值傳遞導致物件切割;Java 全參考傳遞犧牲效能。C# 讓你依型別職責選擇:
實值型別 = 儲存資料;參考型別 = 表現行為。
private MyData _data;
public MyData Foo() => _data; // 實值型別:回傳副本,安全封裝
// 參考型別:洩露內部參考,破壞封裝
若需回傳參考型別且保護封裝,須 Clone() 產生副本,但配置額外堆積物件、需執行期型別檢查、效能低落。
private MyType _impl;
public IMyInterface Foo() => _impl; // 回傳介面,隱藏具體型別,存取行為而非資料
// MyType 應為參考型別:職責在行為多型,非資料儲存
class C { private MyType _a, _b; }
var c = new C();
// MyType 為實值型別:1 次堆積配置,大小 = 2 × sizeof(MyType),內嵌儲存
// MyType 為參考型別:3 次堆積配置(C + _a + _b),各 8 位元組參考指標
陣列更明顯:MyType[100] 實值型別 = 1 次配置 100 個實體;參考型別 = 1 次配置 100 個 null 參考,後續 100 次逐一配置實體 → 碎片化、效能差。
// 版本 1:實值型別
struct Employee { public decimal Salary; public void Pay(Account a) => a.Balance += Salary; }
// 版本 2:改為參考型別加入多型
class Employee { public virtual void Pay(Account a) => a.Balance += Salary; }
既有程式碼:
var e = Employees.Find("CEO");
e.Salary += Bonus; // 版本 1:修改副本;版本 2:修改原物件 → CEO 永久加薪!
行為劇變,編譯器不警告,只在執行期產生 Bug。
任何一項 NO → 參考型別。拿不準時 → 參考型別。