將 Employee 從實值型別(struct)改為參考型別(class),會擾亂所有現有程式碼:回傳值從值傳回變為參考傳回,參數從傳值變為傳參考。以下程式碼行為將大幅改變:
Employee e1 = Employees.Find("CEO");
e1.Salary += Bonus; // Add one time bonus.
e1.Pay(CEOBankAccount);
原本一次性加入紅利的操作,變成持續性調薪。原為值複製之處,如今成參考。編譯器樂意配合,CEO 更樂意,但 CEO 會回報 Bug。問題根源在於 Employee 不再遵循實值型別語意。
定義為 Employee 的資料儲存元素,若添加「發薪水」職責,屬於類別範疇。類別可多型實現常見職責;結構不應允許,應僅限於儲存資料。
.NET 文件建議以型別大小為決策因素,但實際上「型別用途」更關鍵。簡單結構或單純資料載體是實值型別優秀候選。實值型別在記憶體管理上表現優異:少堆積碎片、少垃圾產生、少間接存取。(譯註:垃圾指堆積上無法存取、等待 GC 回收的物件。)
從方法或屬性回傳時,實值型別會複製資料,避免暴露內部結構風險。但你付出的代價是功能受限:實值型別在物件導向技術支援有限,應視為封閉型別。雖可實作介面,但需裝箱(原則 17 將說明效能損失)。請將實值型別視為資料容器,而非 OO 物件。
若對下列問題全答「是」,應建立實值型別:
將實值型別視為低層資料儲存,用參考型別表達應用程式邏輯。從方法取得安全資料副本,從內嵌實值型別獲得記憶體效率,用標準 OO 技術建立邏輯。拿不準時,用參考型別。
class 為參考型別,struct 為實值型別。注意:列舉、委派、事件屬於哪種型別?