代码之家  ›  专栏  ›  技术社区  ›  Carra

不变词典

  •  4
  • Carra  · 技术社区  · 15 年前

    我想知道是否可以创建一个返回只读字典的属性?

        private readonly Dictionary<string, IMyObject> _myDictionary;
        public Dictionary<string, IMyObject> MyDictionary
        {
            get { return _myDictionary; }
        }
    

    因此,不允许使用MyDictionary的用户添加、删除或更改项目。有什么方法可以做到这一点吗?

    6 回复  |  直到 6 年前
        1
  •  7
  •   StayOnTarget Charlie Flowers    6 年前

    我想你需要一门课程来包装 Dictionary ReadOnlyCollection 包裹 List .

    虽然找不到执行此操作的默认类,但您会在以下问题的答案之一中找到一个实现: this 问题。

    BCL Extras Project 还包含这样一个实现。它支持创建代理对象,该代理对象实现 IDictionary 并且可以在它的位置上使用。

        2
  •  2
  •   pavel    10 年前

    .Net 4.5:System.Collections.ObjectModel.ReadOnlyDictionary

        3
  •  1
  •   leppie    15 年前

    继承自 System.Collections.ObjectModel.KeyedCollection<TKey,TItem>

    推翻 InsertItem RemoveItem

        4
  •  0
  •   Community CDub    8 年前

    C#并没有提供一种完全按照您建议的方式来实现这一点的方法,但是您可以返回一个“自制”的不可变字典,它可以包装您的myDictionary。

    有关创建不可变字典的更多信息,请查看此文档。

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

        5
  •  0
  •   Amy B    15 年前

    如果提供此不可变词典的目的是保护您自己的词典,只需给它们一个浅拷贝即可。

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

    当然,调用方仍然可以访问字典中的内容,并且可能会对它们进行变异。如果这是一个问题,做一个深度拷贝。

        6
  •  0
  •   sra Jon    13 年前

    /// <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.");
        }
    }