C#的未來:不可變類

ngmm 9年前發布 | 4K 次閱讀 C#

英文原文:C# Futures: Immutable Classes

本文是 C# 的未來系列文章的最后一篇了,這次我們將討論第 159 號提案,它建議在編譯器中加入對不可變類的支持。雖說在 C# 中創建不可變類型一直以來都是可以做到的,并且C# 6 還將進一步簡化這一過程,但目前還沒有一種方式能夠“將類聲明為不可變”,并讓編譯器對這一聲明進行校驗。

這一提議看起來似乎并非十分重要,因為對類進行手動檢查也不是非常困難的事。但如果缺少了對于不可變性的某種聲明,就難以了解開發者的意圖。應 用程序的開發者可能會做出某些假設,例如可以在多線程環境中安全地使用某個類,卻發現在下一個版本中,類庫的開發者為其加入了某個屬性的 setter 方法,或是其它任何一種可變的、非線程安全的特性。

第 159 號提議推薦通過使用一個“immutable”關鍵字或者屬性,顯式地表明某個類型在任何情況下都不能更改。此外,一個不可變對象只能夠引用其它不可變對象。

不可變對象的構造函數也具有一些限制,尤其是它們不能夠通過“this”變量調用方法,因為這有可能將該對象在構造過程完成之前“泄漏”出去,從而破壞了對不可變性的承諾。至于這種泄漏應當引起一個錯誤還是一次警告,這一點可以再議。Sam Harwell 寫道:

我比較傾向于發出警告的做法,雖然這種做法并不常見,并且也不是推薦的編碼方式,但也很難肯定地說絕對沒有人需要編寫這樣的代碼。

不可變性與 Pure

第一眼看上去,不可變性與 Pure(純對象或方法)約束的作用似乎是相同的,但它們之間確實存在著一些重要的不同之處。

  • 一個純對象可以引用其它并未標注為 Pure 的對象,而正如之前所說,不可變類型不允許引用可變類型。
  • 純方法不允許進行任何可見的狀態更改,包括對當前對象與任何參數的更改。
  • 純方法或純屬性可以更改內部狀態。舉例來說,它可以將某個計算的結果進行緩存以便重用。這一點并不違反純方法的承諾,因為外部的觀察者不會察覺到內部的變化。而不可變對象則沒有這種能力。
  • 不可變對象中的方法只保證不會更改對象的狀態,但允許對輸入參數的狀態進行更改。

考慮到這些不同之處的存在,相信你會看到許多同時具有不可變性與 Pure 特性的對象。

泛型與不可變性

泛型類型也將支持不可變性。要實現這一點,通常需要為每個類型參數都設定一個不可變性的限制。但這一條規則還有待商榷,有人認為可以直接從類型的參數中推斷出不可變性,而無需顯式地將其列為不可變。

欺騙

在某些情況下,你必須對類型系統進行欺騙,這一點已經得到了認可。打個比方,ImmutableArray 是對一個普通數組的封裝。而如果按照這條提議的基本原則來說,這種行為是不允許出現的。為了處理這種場景,你可以在這個類的標注中進行聲明,表示你是有意 地違背了這條原則,并且已經仔細地考慮過這樣做的后果。這種做法與“unsafe”關鍵字的行為很相似,因為后者也是為了這種場合才出現的。

由于“unsafe”關鍵字的意思已經固定了,因此該提議考慮使用其它的關鍵字。目前來說,得到最多認可的關鍵字是“mutable”,不過看起來大家對此都不是十分滿意。

只讀性 —— 隱式或顯式

在一個不可變對象中,每個字段在語義上都是只讀的。某些開發者認為不必顯式地進行聲明,這可以減少代碼的冗長度。另一些人則認為,正如在靜態類中聲明靜態字段一樣,每個字段都應該顯式地標注為只讀。

內部或外部校驗

具體在何處強制不可變性,這一點需要認真考慮。某些人認為,正如代碼契約與 Pure 屬性一樣,不可變性也應當由某個外部分析器進行處理。這樣一來,開發團隊就能夠自行決定是否需要以編程方式強制不可變性。

另一部分開發者則認為,正因為如此,不可變性更不應當由外部工具進行處理。他們希望編譯器能夠進行不可變性的檢查,這樣就不會在無意中破壞了它的不可變性。

來自于微軟的 Jared Parsons 寫道:

我認為在這種場合使用分析器是錯誤的方案,在一個單一的 C# 項目中,要強制一系列規則的應用,甚至是對某種 C# 的變體進行分析,分析器都是一種優秀的選擇。因為我對編譯過程具有掌控權,因此可以隨意地選擇并使用分析器。

而如果需要在多個項目中強制某些規則,尤其是在這些項目屬于不同開發者的情況下,分析器的作用就降低了。沒有什么機制能夠強制對某個項目引用通過某種分析器進行掃描,這種情況下唯一有效的強制措施就是雙方的攜手合作了。

這種情況與 Pure 屬性的承諾不同,后者只是表示在某個對象中的任何方法或是屬性都不會“產生任何可見的狀態更改”。

來自: InfoQ

 本文由用戶 ngmm 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!