發表文章

目前顯示的是 9月, 2019的文章

C# 物件屬性的建構賦值與初始化 - C# constructor and object initializer

圖片
寫這篇是起因於在臉書討論C# DTO時我講了"建構賦值比物件初始化優先"這句話(其實我的意思是指先執行),不明白的人請我解釋是甚麼意思,所以就完整交代一下個人設計DTO物件的心得。 當然,若設計其他非DTO物件會更複雜一些... DTO不宜設計成一個複雜的邏輯物件,一般來說我們設計DTO物件時主要是做關於[屬性]的驗證和存取層級的規格設定。 另外,屬性的驗證應止於型別與範圍的安全,所以我們用屬性的get和set方法就可以達到這個需求。 設計每個DTO首先都要面臨3個課題,如下: 1.參考型別的屬性建構時是否實例化。 2.屬性型別與範圍的安全驗證。 3.屬性值的存取保護。 DTO要做到上述課題的完美解答,設計者除了要對物件導向的精神有足夠的認知與內化,還需要正確掌握C#語言的執行方式。這裡提供兩個觀念和技巧﹔ 1.要清楚DTO實例化的過程(C#建構函式與初始化程式碼區塊{}的執行順序) 有幾個重點: 1.屬於參考型別的屬性(例如List<T>)若沒有先實例化就沒辦法使用其API。 2.物件初始化語法區塊中無法執行類似 "new myClass{ myList[0] = "my string", ...}" 這樣編譯器會報錯,因為參考型別的實例化必須等到物件本身完成實例化之後,所以物件初始化要賦值屬性時不能參考到其資料結構,就算程式碼已宣告其值都要等到初始化後才能使用。類似以下例子: 2.更進階的觀念:讓關鍵屬性私有化並限制只能於建構時期賦值 由於物件建構階段比物件初始化階段先完成,所以相同屬性若在建構賦值之後會又被初始化覆蓋。 為了保護建構值我們可以在屬性private set中設計驗證程式碼,然後在建構函式傳入值到setter時驗證後才設定其值。這樣建構函式本身簡潔乾淨,屬性值又不會被初始化覆蓋或後續從外部修改。類似以下例子: 寫在最後 也許目前為止看似一切都妥當,但若是遇到非DTO而是較複雜的物件設計,程式常常會由不同程式人員維護,可能會在程式某處重複設定屬性myList的值,而我們本意是只能在建構時以參數設定myList。 有沒有方法保護程式碼呢? 答案是肯定的。 作法是把負責建構關鍵組態的程式設計