2011-05-26 39 views
3

位奇數一個如此...鎖定對象,以防止任何數據改變

可以說我有以下類:

public class Wibble 
{ 
    public string Foo {get;set;} 
    public string Bar {get;set;} 
} 

此類用於一種工藝,其中的Foo的值和酒吧更新/更改。但是,在過程中的某個點之後,我想「鎖定」實例以防止發生任何更改。所以問題是如何最好地做到這一點?

了各種各樣的解決辦法是這樣的:

public class Wibble 
{ 
    private string _foo; 
    private string _bar; 

    public bool Locked {get; set;} 

    public string Foo 
    { 
    get 
    { 
     return this._foo 
    } 
    set 
    { 
     if (this.Locked) 
     { 
      throw new ObjectIsLockedException() 
     } 

     this._foo = value; 
    } 
    } 

    public string Bar 
    { 
    get 
    { 
     return this._bar 
    } 
    set 
    { 
     if (this.Locked) 
     { 
      throw new ObjectIsLockedException() 
     } 

     this._bar = value; 
    } 
    } 
} 

然而,這似乎有點不雅。

想要做到這一點的原因是我有一個應用程序框架,使用外部開發的插件使用類。 Wibble類被傳遞給插件,但其中一些不應該改變內容,其中一些可以。這背後的意圖是捕捉開發集成問題而不是運行時生產問題。讓對象「鎖定」允許快速識別未按指定編碼的插件。

+0

這讓我想起Eric Lippert所說的「冰棒不變性」。請參閱:http://blogs.msdn.com/b/ericlippert/archive/2011/05/23/read-only-and-threadsafe-are-different.aspx和http://blogs.msdn.com/b/ ericlippert/archive/2007/11/13/immutability-in-c-part-one-of-immutability.aspx – 2011-05-26 13:40:15

+0

我問了一個類似的問題,Lippert先生提供了一個很好的描述,對於。我還發布了一個我最終使用的例子。 http://stackoverflow.com/questions/4168382/immutable-views-of-mutable-types – 2011-05-26 14:59:10

回答

2

我實現了類似的鎖定模式的東西,而且還能夠與包含實際數據類專用子類中實現的,這樣你就可以傳遞出一個只讀接口什麼顯然是數據的只讀視圖,哪些不能上傳到原始的「可變版本」。鎖定純粹是爲了防止數據提供者在提供不可變視圖後進行進一步更改。

它工作得相當好,但有點尷尬,正如你所說的。我認爲有可變的'生成器'對象,然後可以生成不可變的快照,實際上是更清潔。認爲StringBuilder和字符串。這意味着你需要複製一些屬性代碼,並且必須編寫例程來進行復制,但在我看來,這並不像在每個屬性上都有寫入鎖那樣尷尬。在編譯時也很明顯,快照應該是隻讀的,Builder的用戶不能修改它先前創建的快照。

0

你不能使一個對象不可變!

你可以按照這個帖子:

How do I create an immutable Class?

但我認爲你總是可以通過反射更改屬性值!

更新

」 ......其實,string對象都不是一成不變的 和據我所知,至少有2種方式,打破字符串 不變性。隨着指針作爲該代碼示例所示並與一些先進的System.Reflection使用......」

http://codebetter.com/patricksmacchia/2008/01/13/immutable-types-understand-them-and-use-them/

+2

字符串是不可變的 – rerun 2011-05-26 13:36:32

+0

我更新了文章 – danyolgiax 2011-05-26 13:46:52

+0

在.NET中,當完全信任的運行時,你可以做任何你想做的事。你可以使用指針在你想要的任何位置寫入。以完全信任方式運行意味着您關閉了.NET的安全機制,並且仍然需要反射或指針來寫入不可變結構。這不是我們所說的'不變的',因爲那是在作弊並在腳下開槍。所以,儘管我們事實上可以改變一切,但我們認爲'字符串'是不可變的。即使是Pattrick Smacchia的文章,你所說的「字符串」是不可變的。 – Steven 2011-05-26 13:51:48

1

我會推薦這:

一個不可變的基類:

public class Wibble 
{ 
    public string Foo { get; private set; } 
    public string Bar { get; private set; } 

    public Wibble(string foo, string bar) 
    { 
    this.Foo = foo; 
    this.Bar = bar 
    } 
} 

然後一個可變類,你可以改變,然後在時機成熟時創建一個不可改變的副本。

public class MutableWibble 
{ 
    public string Foo { get; set; } 
    public string Bar { get; set; } 

    public Wibble CreateImmutableWibble() 
    { 
    return new Wibble(this.Foo, this.Bar); 
    } 
} 

我完全記不起C#語法,但你明白了。

延伸閱讀:http://msdn.microsoft.com/en-us/library/acdd6hb7%28v=vs.71%29.aspx

+0

我實際上不會建議讓Wibble成爲基類,因爲它只是介紹將MutableWibble作爲Wibble傳遞的可能性,這意味着給定的Wibble實例可能是也可能不是可變的。 – 2011-05-26 13:44:45

+0

@Dan:我修復@ Joe的回答,並刪除了基類,因爲那樣做根本就不會按照他想要的方式工作。沒有基類(以及對代碼的一些更改)它現在可以工作。 – Steven 2011-05-26 13:47:10

+0

@Steven - 是的,這很愚蠢,謝謝修理。我添加了「只讀」作爲事後的想法。但我堅持擁有不可變的基類。斯卡拉這樣做,例如與HashMap和Objective-C做到了這一點,例如與NSMutableArray(雖然實施非常混亂)。我不想進入編輯戰爭,但我會堅持擁有一個不可變的基類。 – Joe 2011-05-26 14:58:01

0

您擁有的另一個選項是使用BinaryFormatter創建要鎖定的對象的成員副本。雖然你沒有鎖定對象,但你創建的快照可以在原始文件保持不變的情況下丟棄。