封装私有成员变量的修改方式,但允许成员可以读取

时间:2014-04-25 20:59:11

标签: c# oop encapsulation

这是一个非常基本的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上,所以我选择的答案可能无法反映未来读者的最佳解决方案。

3 个答案:

答案 0 :(得分: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;
}

如果您将对象暴露给第三方代码,例如潜在的恶意插件,您真的想避免这种情况。此外,您将不得不撤销反射权限,因为否则第三方代码仍然可以抓住您的私人字典或打开只读包装并修改它。

答案 1 :(得分: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 :(得分: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
        }
    }
}