开发者

Unchangeable Dictionary

I'm wondering if I can create a Property that returns a read-only Dictionary?

Example:

开发者_StackOverflow社区
    private readonly Dictionary<string, IMyObject> _myDictionary;
    public Dictionary<string, IMyObject> MyDictionary
    {
        get { return _myDictionary; }
    }

Therefore people using MyDictionary are not allowed to add, remove, or change items. Any way in which this can be done?


I think that you'll need a class that wraps a Dictionary like the ReadOnlyCollection wraps a List.

While you will not find a default class that does this, you'll find an implementation in one of the answers to this question.

The BCL Extras Project also contains such an implementation. It supports the creation of a proxy object which implements IDictionary and can be used in its place.


.Net 4.5: System.Collections.ObjectModel.ReadOnlyDictionary


Inherit from System.Collections.ObjectModel.KeyedCollection<TKey,TItem>

Override InsertItem and RemoveItem


C# doesn't provide a way of doing this exactly the way you suggest, but you could always return a "home-made" immutable dictionary that wraps your myDictionary.

Have a look at this for more info on creating an immutable dictionary.

Does C# have a way of giving me an immutable Dictionary?


If the intent of providing this immutable dictionary is to protect your own dictionary, just give them a shallow copy.

public Dictionary<string, IMyObject> MyDictionary 
{ 
    get { return new Dictionary<string, IMyObject>(_myDictionary); } 
} 

Caller may add and remove whatever, but it won't matter for your dictionary.

Of course, the caller still has access to the things in the dictionary and may mutate them. If that's a problem, make a deep copy.


Here's a implementation that I use for all those who need a ready to got snippet

/// <summary>
/// Read only wrapper for generics based dictionary.
/// Only provides lookup retrieval abilities.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
public class DictionaryReadOnly<TKey, TValue> : IDictionary<TKey, TValue>
{
    #region Private Members

    private IDictionary<TKey, TValue> _item;
    private bool _throwOnWritableAction = false;

    #endregion

    #region Constructors

    /// <summary>
    /// Constructor requiring the generic dictionary being wrapped.
    /// </summary>
    /// <param name="item"></param>
    public DictionaryReadOnly(IDictionary<TKey, TValue> items)
    {
        _throwOnWritableAction = true;
        _item = items;
    }

    /// <summary>
    /// Constructor requiring the generic dictionary being wrapped.
    /// </summary>
    /// <param name="item"></param>
    public DictionaryReadOnly(IDictionary<TKey, TValue> items, bool throwOnWritableAction)
    {            
        _throwOnWritableAction = throwOnWritableAction;
        _item = items;
    }
    #endregion

    #region IDictionary<TKey,TValue> Members

    /// <summary>
    /// Number of items in the dictionary.
    /// </summary>
    public int Count
    {
        get { return _item.Count; }
    }

    /// <summary>
    /// Determine if the underlying collection contains the key.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool ContainsKey(TKey key)
    {
        return _item.ContainsKey(key);
    }

    /// <summary>
    /// Returns the value associated with the key.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public TValue this[TKey key]
    {
        get { return _item[key]; }
        set
        {
            CheckAndThrow("Set");
        }
    }

    /// <summary>
    /// Return keys.
    /// </summary>
    public ICollection<TKey> Keys
    {
        get { return _item.Keys; }
    }

    /// <summary>
    /// Not-supported.
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public void Add(TKey key, TValue value)
    {
        CheckAndThrow("Add");
    }

    /// <summary>
    /// Not-supported.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Remove(TKey key)
    {
        CheckAndThrow("Remove");
        return false;
    }

    /// <summary>
    /// Try to get the value.
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public bool TryGetValue(TKey key, out TValue value)
    {
        value = default(TValue);

        if (_item.ContainsKey(key))
        {
            value = _item[key];
            return true;
        }
        return false;
    }

    /// <summary>
    /// Get the values.
    /// </summary>
    public ICollection<TValue> Values
    {
        get { return _item.Values; }
    }

    #endregion

    #region ICollection<KeyValuePair<TKey,TValue>> Members

    /// <summary>
    /// Not-supported.
    /// </summary>
    /// <param name="item"></param>
    public void Add(KeyValuePair<TKey, TValue> item)
    {
        CheckAndThrow("Add");
    }

    /// <summary>
    /// Not-Supported.
    /// </summary>
    public void Clear()
    {
        CheckAndThrow("Clear");
    }

    /// <summary>
    /// Determine whether key value pair is in dictionary.
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return _item.Contains(item);
    }

    /// <summary>
    /// Copy items to the array.
    /// </summary>
    /// <param name="array"></param>
    /// <param name="arrayIndex"></param>
    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        this._item.CopyTo(array, arrayIndex);
    }

    /// <summary>
    /// Indicate read-only
    /// </summary>
    public bool IsReadOnly
    {
        get { return true; }
    }

    /// <summary>
    /// Non-supported action.
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        CheckAndThrow("Remove");
        return false;
    }

    #endregion

    #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    /// <summary>
    /// Get the enumerator.
    /// </summary>
    /// <returns></returns>
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _item.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members
    /// <summary>
    /// Get the enumerator.
    /// </summary>
    /// <returns></returns>
    IEnumerator IEnumerable.GetEnumerator()
    {
        return _item.GetEnumerator();
    }

    #endregion

    /// <summary>
    /// Check and thrown based on flag.
    /// </summary>
    /// <param name="action"></param>
    void CheckAndThrow(string action)
    {
        if (_throwOnWritableAction)
            throw new InvalidOperationException("Can not perform action : " + action + " on this read-only collection.");
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜