C#的未來:擴展屬性及更多
英文原文:C# Futures: Extension Properties and More
C#未來系列文章中的下一條提議希望能夠使用擴展屬性。這一功能是大家期盼已久的特性,但通常來說被認為是不可行的,因為它會帶來內存泄露。
實際上,實現擴展屬性所需的基礎功能在 .NET 4.0 中就已經具備了。這里的秘密在于,你可以使用某個 ConditionalWeakTable 類以保存對象與擴展字段之間的映射。其實創建 ConditionalWeakTable 的目的正是為了提供這種動態類型語言的功能。
Sam Harwell 為我們演示了如何正確地使用這個類:
private static readonly ConditionalWeakTable> _extensionField_f; public static FieldType get_f(T obj) { StrongBox box; if (!_extensionField_f.TryGetValue (obj, out box)) return default(FieldType); return box.Value; } public static void set_f(T obj, FieldType value) { StrongBox box = _extensionField_f.GetOrCreateValue (obj); box.Value = value; }
擴展類
以上這種方式雖然能夠實現最終的目的,但它的語法并不簡潔。因此一種被稱為“擴展類”的概念就能夠派上用場了。可以通過以下語法定義一個擴展類:
public extension class MyClassExtensions : MyClass
在 MyClassExtensions 中定義的每個方法或屬性都會自動成為 MyClass 中的擴展方法或屬性。在 MyClassExtensions 中定義成員看起來與在 MyClass 中直接定義成員沒有任何差別。這種方式讓你能夠避免使用舊的語法,即將某個方法定義為靜態方法,并在參數中包含一個“this”關鍵字。
在擴展類中定義的字段和事件將通過上述的 ConditionalWeakTable 所實現。屬性可以明確指定對應的字段或是自動實現,在后一種情況下,其內部實現依然依賴于 ConditionalWeakTable 的使用。
靜態擴展
由于擴展類概念的存在,使得一種被稱為“靜態擴展方法”的使用方式也成為可能。它允許你為某個類添加一個靜態方法,與你為對象添加成員方法的方式相同。
為了澄清這種用法,Erik Schierboom 這樣寫道:
比方說,它能夠允許我擴展 xUnit 中的 Assert 類。
</blockquote>思考
雖然這種做法在動態類型語言中很常見,但這種能夠為某個類任意添加狀態的能力還是讓某些開發者感到有些不安。HellBrick 總結了人們對于擴展字段的顧慮:
看上去對這種功能的嘗試是很自然的事,但我擔心這個特性可能會很容易遭到誤用。如果你想要為某個類的實例附加一個額外的狀態,我認為在大部分情況下,更好的方式是繼承這個類,或是為它創建一個包裝器。無論是哪種做法,你的意圖都很明確。使用某種像魔法一樣自動附加的弱字段引用,就不清楚它的生命周期,將這種方式作為類的設計方式或許是一種非常廉價的方案,并且具有一定吸引力。但同時,它可能會導致出現一些復雜的代碼,增加日后維護的困難。
</blockquote>對上述說法的一種反對意見認為,如果沒有擴展字段,那么也不可能通過擴展提供自動屬性。Chrisaut 繼續這個討論:
即使擴展字段這條提議通不過,只要屬性的 setter 仍然是允許使用的,就會有開發者嘗試著提出自己的解決方案,而其中有半數都存在著一些微秒的錯誤。比方說,他們可能會創建一個 Dictonary<MyClass, string>并保存在屬性中。額……這樣一來這個實例就永遠不會被垃圾回收了,這將帶來內存泄露。大多數開發者甚至不知道弱引用和 ConditionalWeakTable 的存在。
因此如果我們真的要阻止附加額外狀態的行為(也就是不希望引入擴展字段),那么我感覺唯一的方法就是明確地表示只允許屬性的 getter,不支持屬性的 setter,或者在自動屬性中只支持 getter。
這樣一來大概就可以了。但我猜使用者會試圖打破這一限制,我不確定只支持 getter 是否能夠涵蓋用戶所需的所有場景。或者我們也可以說它已經涵蓋了足夠多的場景,而剩余的部分不值得實現。
</blockquote>擴展字段的另一個問題是對可回收對象的存儲。如果你在 ConditionalWeakTable 中保存了一個可回收(disposable)對象,你需要找到一種方式,在父對象被垃圾回收時顯式地回收該對象。 ConditionalWeakTable 不會自動為你實現這一功能,而依賴于終結器又存在著風險。
來自: InfoQ本文由用戶 cbgd 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!