2014-04-25 15 views
0

這是一個非常基本的OOP問題。我不想做一個_objectSettings的副本,並覺得我有一個大腦放屁。這個問題可以在對象的Getter函數中看到。封裝如何修改私有成員變量,但允許成員可以讀取

例子:

public class CoolObject 
{ 
    private Dictionary<long, bool> _objectSettings; 
    public CoolObject(){ 
     //.. do stuff// 
    } 
    public void UpdateSettings(long, bool){ 
     // enforce new setting obey's some rules 
    } 
    public Dictionary<long,bool> GetSettings(){ 
     // return Dictionary of settings, but not allow users to modify _objectSettings 
    } 
} 

謝謝:)

編輯:我在.NET 4.0,所以我選擇答案可能不反映未來的讀者最優化的解決方案。

+0

你需要序列化的詞典:http://msdn.microsoft.com/en-us/library/ms233843.aspx – SamFisher83

+0

你想要的任何變化*你*讓通過'_objectSettings'是可見任何已經調用GetSettings的代碼? –

+2

@ SamFisher83:這裏不需要序列化。 –

回答

2

要麼複製或包裝您的字典ReadOnlyDictionary需要.NET 4.5,但如果您不在.NET 4.5上,則可以輕鬆實現自己的目錄。

public Dictionary<Int64, Boolean> GetSettings() 
{ 
    // Return a snapshot of the current settings. 
    return new Dictionary<Int64, Boolean>(this._objectSettings); 
} 

public ReadOnlyDictionary<Int64, Boolean> GetSettings() 
{ 
    // Return a read-only wrapper around the current settings. 
    return new ReadOnlyDictionary<Int64, Boolean>(this._objectSettings); 
} 

所有呼叫者會看到修改與後來選項的設置,同時獲得快照後對設置進行修改,將不與選擇前者可見。

如果您想防止在您自己的代碼庫中進行無意修改,提及的兩個選項都可以,但您也可以使用返回類型IReadOnlyDictionary<TKey, TValue>IEnumerable<KeyValuePair<TKey, TValue>>以較弱的保護形式逃脫。調用者可以將其重新設置爲Dictionary<TKey, TValue>並進行修改,但這在您自己的代碼庫中並不是一個大問題。

public IReadOnlyDictionary<Int64, Boolean> GetSettings() 
{ 
    // Just return the dictionary with property type IReadOnlyDictionary`2 but 
    // then evil callers can still do the following. 
    // ((Dictionary<Int64, Boolean>)coolObject.GetSettings()).Clear(); 
    return this._objectSettings; 
} 

如果暴露對象的第三方代碼,例如潛在的惡意插件,你真的想避免這種情況。此外,您將不得不撤銷反射權限,否則第三方代碼仍然可能只是抓住您的私人字典或打開只讀包裝並修改它。

+0

這兩個選項意味着通過對象契約可以改變字典,但事實上它不能,雖然我懷疑第二個選項是爲了重新生成一個'ReadOnlyDictionary'而不是'Dictionary'。 –

+0

謝謝,那是一個複製粘貼錯誤。 –

0

嘗試返回IReadOnlyDictionary

public IReadOnlyDictionary<long,bool> GetSettings(){ 
    return _objectSettings; 
} 

該界面由Dictionary實現,不允許更改詞典。

[SerializableAttribute] 
[ComVisibleAttribute(false)] 
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, 
    ICollection<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, 
    IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, 
    IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, ISerializable, 
    IDeserializationCallback 
+2

我不認爲這是一個好的解決方案,調用者可以簡單地將其恢復。 –

+1

@DanielBrückner:調用者也可以使用反射來訪問私人支持存儲。合同就是這樣一個關於如何使用對象接口的協議。 –

+0

這需要反映許可。如果您必須真正保護您的數據,例如防止潛在的惡意插件,則您確實需要發放副本或只讀包裝並撤銷反射權限。 –

0

您可以通過使setter爲private並通過構造函數注入該值來使該類不可變。

public class CoolObject 
{ 
    public CoolObject(ImmutableSortedDictionary<long, bool> objectSettings){ 
     ObjectSettings = objectSettings; 
     //.. do stuff// 
    } 

    public ImmutableSortedDictionary<long,bool> ObjectSettings 
    { 
     get 
     { 
      // return Dictionary of settings, but not allow users to modify _objectSettings 
     } 

     private set 
     { 
      // enforce new setting obey's some rules 
     } 
    } 
} 
+0

'coolObject.ObjectSettings。清除();'和所有設置都不見了...... –

+0

@DanielBrückner,這是正確的。應該使用ImmutableSortedDictionary。我已經更新了答案。 –