2011-03-06 89 views
4

我喜歡能夠爲可以使用的類提供默認值,但問題是如果它們被更改,那麼它將影響對它的所有引用並且不會是「默認」。通過使用像這樣的默認值,它可以節省內存,並允許默認值(如果需要)傳播到所有使用默認值的引用。靜態不可變的默認實例

一個簡單的例子是

class A 
{ 
    static public A Default; 
} 

然後可以使用A.Default作爲A的「默認」的實例同樣,問題是,A是不是一成不變的或者至少是「凍結」並變爲它會改變所有的參考。如果這是人們想要的行爲,這可能很好,但如果默認情況下發生了意外更改,可能會造成嚴重破壞。

我真正需要的是一種深度凍結和解凍Default的方法。

很明顯,一種方法是簡單地讓所有setter只在一個條件上設置並將collection標記爲只讀。提供這樣簡單的行爲似乎有很多重複的工作。

有沒有一個簡單的庫,模式或反射來完成這個?寫入時複製能力會很好,所以如果試圖改變Default,就會創建一個新的可變實例。不僅如此,即使flyweight實例可以創建,如果它有機會提高性能(更改的大小)。

示例:假設您最初創建1M個具有所有相同狀態的大(內存大小)對象。通過使用默認模式,這隻會創建1個實際的對象。假設你改變了所有狀態的1個參數(比如位置),但對象本身非常大。使用flyweight模式,您只需1M個已更改的參數即可跟蹤(較慢但內存較少),而不是1M個新對象。在改變了足夠的參數之後,完整的對象最終被分配給它的引用。

這裏有什麼嗎?

+1

在什麼情況下,你會想「解凍」默認與誰應該可以「解凍」默認? – shahkalpesh 2011-03-06 15:56:33

+0

你確定你確實需要這個複雜的東西嗎? – 2011-03-06 16:00:57

+0

這似乎是一個設計缺陷。你有一個類A,當它的「Default」實例不可變時,它是不可變的。Perhapes你需要兩個類,一個不可變和可變的,或者讓你的類A成爲一個結構體或值類型,比如object(即像String) – MerickOWA 2011-03-06 16:15:25

回答

0

沒有什麼像現成的盒子可用。您需要創建自己的寫時拷貝實例和代碼。

旅遊真正寫入時複製行爲做:

  • 創建一個小的「參照」對象,每一次有人讀了「Default」屬性返回它的一個新的實例。這個對象總是引用相同的(私有的,按定義只讀)內部數據。

  • 無論何時數據發生變化,並且您仍在只讀數據上,請創建內部數據的副本並將其分配給您的參考對象。

.NET Framework設計人員爲一些類似需求的類採用了更明確的路由。例如,如果您看到CultureInfo,「默認」實例是隻讀的,並且如果您嘗試修改這些,則會發生異常。但是,您可以輕鬆創建可變副本(其中一個構造函數接受另一個CultureInfo實例)。

+0

是的,但我不知道如何在一般和有效的情況下完成這樣的事情。一個案件​​並不難,但如果你必須一直這樣做,那就是一團糟。他們是如何實現其只讀默認值的?看他們說的幫助,他們使用了一個包裝,但是這個包裝完成了很長的路還是什麼? – AbstractDissonance 2011-03-06 16:33:26

+0

如果你必須一直這麼做,那麼你的設計可能會出錯。關於MS和'CultureInfo'等,從我可以告訴他們明確實現了包裝。無論如何,總是有可能使用代碼生成工具,它使用模板生成樣板代碼,這樣基本上只會編寫一次模板,然後生成代碼。或者,您可以使用抽象類或接口,並在運行時用Reflection.Emit來生成代碼......有很多可能性。 – Lucero 2011-03-07 00:40:40

0

有幾個方法可以做到這一點,映入腦海:

  1. 有一個名爲IsReadOnly標誌,使得所有的存取器(即可以改變一個實例的setter和方法)拋出一個異常時,這是真的。將使用IsReadOnly設置爲true來創建您的Default實例。

  2. 創建一個基類(FooReadOnly),其中所有的增變器都會拋出異常,然後創建增效器工作的派生類(Foo)。您的Default實例的類型爲FooReadOnly

0

您可能會了解DependancyObject(s)和DependanceProperty如何在WPF/Silverlight中工作。

下面是它在WPF/Silverlight中是如何工作的一類「A」與屬性「富」與5

class A : DependancyObject { 
    static DependancyProperty PropertyFoo = DependanceProperty.Register("Foo", typeof(int), typeof(A), new PropertyMetadata(5)); 

    int Foo { 
    get { return (int)GetValue(PropertyFoo); } 
    set { SetValue(PropertyFoo, value); } 
    } 

的缺點是,你必須「手動默認值的示例「實現你的屬性,你不能利用簡單的」int Foo {get; set;}「語法,但是代碼片段可以幫助你很多。

很顯然,如果你不想使用WPF或Silverlight你必須實現這一切你自己,但你得到了以下優點。

因爲,DependancyProperties是對象,他們可以持有可通過尚未overrided價值的任何DependancyObject共享它們的默認值。

DependancyObjects只保留一個值變化值的列表,以便是一樣的默認情況下使用起來沒有多餘的內存對象。

由於所有屬性設置的經歷DependancyObject.SetValue,它很容易在一個地方實現邏輯作出某些屬性或整個對象只讀。

還有其他的優點/功能可能類似性質等的動畫加入,但是,如果你實現它,你可以保持它的簡單/複雜,因爲你想要的。

2

一個我可能使用的方法是實現一個只讀接口和改變靜態默認返回類型是:

interface ISomeClass 
{ 
    string MyProperty { get; } 
} 

class SomeClass : ISomeClass 
{ 
    string MyProperty { get; set; } 

    public static ISomeClass Default = new SomeClass(); 
} 

然後,您可以強制執行所需要的默認隨時更改,一個可變參考 明確要求,也許是單獨的方法:

 public static SomeClass GetMutableDefault() 
     { 
      return Default as SomeClass; 
     } 

然後你得到編譯時檢查正在試圖改變一個SomeClass的實例的任何方法不使用默認值,除非明確規定是這麼說的。