.net NET中是否有只读的通用词典?

.net NET中是否有只读的通用词典?,.net,dictionary,readonly,.net,Dictionary,Readonly,我正在返回对只读属性中词典的引用。如何防止消费者更改我的数据?如果这是一个IList,我可以简单地将它返回为AsReadOnly。我能用字典做些类似的事情吗 Private _mydictionary As Dictionary(Of String, String) Public ReadOnly Property MyDictionary() As Dictionary(Of String, String) Get Return _mydictionary En

我正在返回对只读属性中词典的引用。如何防止消费者更改我的数据?如果这是一个
IList
,我可以简单地将它返回为
AsReadOnly
。我能用字典做些类似的事情吗

Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
    Get
        Return _mydictionary
    End Get
End Property

您可以创建一个只实现字典部分实现的类,并隐藏所有添加/删除/设置函数

在内部使用字典,外部类将所有请求传递给该字典


但是,由于您的字典可能包含引用类型,因此您无法阻止用户对字典所包含的类设置值(除非这些类本身是只读的)

否,但是您可以轻松地滚动自己的类。IDictionary没有定义IsReadOnly属性。只需包装一个字典,并从相应的方法中抛出NotSupportedException即可。

.NET 4.5 .NET Framework 4.5引入了()

由于.NET Framework 4.5 BCL不包括字典的
AsReadOnly
,因此您需要编写自己的字典(如果需要的话)。它将类似于下面的内容,其简单性可能突出了为什么它不是.NET4.5的优先事项

public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary)
{
    return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}
publicstaticreadonlydictionarasreadonly(
这是一本字典
{
返回新的ReadOnlyDictionary(字典);
}
.NET 4.0及以下版本 在.NET4.5之前,没有一个.NETFramework类像包装一样包装a。然而,创建一个并不困难


-如果您愿意,还有很多其他方法。

我认为没有一种简单的方法可以做到这一点……如果您的词典是自定义类的一部分,您可以使用索引器来实现:

public class MyClass
{
  private Dictionary<string, string> _myDictionary;

  public string this[string index]
  {
    get { return _myDictionary[index]; }
  }
}
公共类MyClass
{
私人字典(我的字典),;
公共字符串此[字符串索引]
{
获取{return _myDictionary[index];}
}
}
公共IEnumerable MyDictionary()
{
foreach(mydictionary中的KeyValuePair项)
收益回报项目;
}

BCL中没有可用的。然而,我在我的网站上发布了一个只读字典(名为ImmutableMap)

除了作为一个完全不可变的字典之外,它还支持生成实现IDictionary的代理对象,并且可以在使用IDictionary的任何地方使用。每当调用一个变异API时,它都会抛出异常

void Example() { 
  var map = ImmutableMap.Create<int,string>();
  map = map.Add(42,"foobar");
  IDictionary<int,string> dictionary = CollectionUtility.ToIDictionary(map);
}
void Example(){
var map=ImmutableMap.Create();
map=map.Add(42,“foobar”);
IDictionary dictionary=CollectionUtility.ToIDictionary(地图);
}

IsReadOnly on
IDictionary
继承自
ICollection
IDictionary
扩展
ICollection
ICollection
)。它没有以任何方式使用或实现(实际上通过使用显式实现关联的
ICollection
成员而“隐藏”)

至少有3种方法可以解决这个问题:

  • 实现自定义读取 仅
    i词典
    和 包装/委托给内部 正如所建议的那样
  • 归还
    i收集
    设置为只读或
    IEnumerable
    取决于 价值
  • 使用副本克隆词典 构造函数
    .ctor(IDictionary)
    并返回一个副本-该 用户可以自由使用它的方式 随他们的便,但事实并非如此 对对象状态的影响 托管源字典。注 如果你在查字典的话 克隆包含引用类型( 不是示例中所示的字符串 )你需要复印 “手动”并克隆引用 类型也一样

  • 作为旁白;在公开集合时,目标是公开尽可能小的接口-在示例中,它应该是IDictionary,因为这样可以在不破坏类型公开的公共契约的情况下改变底层实现。

    下面是一个简单的实现,它包装了一个字典:

    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        private readonly IDictionary<TKey, TValue> _dictionary;
    
        public ReadOnlyDictionary()
        {
            _dictionary = new Dictionary<TKey, TValue>();
        }
    
        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        {
            _dictionary = dictionary;
        }
    
        #region IDictionary<TKey,TValue> Members
    
        void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
        {
            throw ReadOnlyException();
        }
    
        public bool ContainsKey(TKey key)
        {
            return _dictionary.ContainsKey(key);
        }
    
        public ICollection<TKey> Keys
        {
            get { return _dictionary.Keys; }
        }
    
        bool IDictionary<TKey, TValue>.Remove(TKey key)
        {
            throw ReadOnlyException();
        }
    
        public bool TryGetValue(TKey key, out TValue value)
        {
            return _dictionary.TryGetValue(key, out value);
        }
    
        public ICollection<TValue> Values
        {
            get { return _dictionary.Values; }
        }
    
        public TValue this[TKey key]
        {
            get
            {
                return _dictionary[key];
            }
        }
    
        TValue IDictionary<TKey, TValue>.this[TKey key]
        {
            get
            {
                return this[key];
            }
            set
            {
                throw ReadOnlyException();
            }
        }
    
        #endregion
    
        #region ICollection<KeyValuePair<TKey,TValue>> Members
    
        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
        {
            throw ReadOnlyException();
        }
    
        void ICollection<KeyValuePair<TKey, TValue>>.Clear()
        {
            throw ReadOnlyException();
        }
    
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _dictionary.Contains(item);
        }
    
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            _dictionary.CopyTo(array, arrayIndex);
        }
    
        public int Count
        {
            get { return _dictionary.Count; }
        }
    
        public bool IsReadOnly
        {
            get { return true; }
        }
    
        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
        {
            throw ReadOnlyException();
        }
    
        #endregion
    
        #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _dictionary.GetEnumerator();
        }
    
        #endregion
    
        #region IEnumerable Members
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        #endregion
    
        private static Exception ReadOnlyException()
        {
            return new NotSupportedException("This dictionary is read-only");
        }
    }
    
    公共类只读词典:IDictionary { 专用只读词典; 公共只读词典() { _字典=新字典(); } 公共只读词典(IDictionary dictionary) { _字典=字典; } #区域索引成员 void IDictionary.Add(TKey键,TValue值) { 抛出ReadOnlyException(); } 公共bool ContainsKey(TKey) { 返回_dictionary.ContainsKey(key); } 公共ICollection密钥 { 获取{return\u dictionary.Keys;} } bool IDictionary.Remove(TKey) { 抛出ReadOnlyException(); } 公共bool TryGetValue(TKey键,out TValue值) { 返回_dictionary.TryGetValue(键,输出值); } 公共ICollection值 { 获取{return\u dictionary.Values;} } 公共TValue此[TKey] { 得到 { 返回字典[键]; } } TValue IDictionary。此[TKey] { 得到 { 返回此[键]; } 设置 { 抛出ReadOnlyException(); } } #端区 #区域i集合成员 void ICollection.Add(KeyValuePair项) { 抛出ReadOnlyException(); } void ICollection.Clear() { 抛出ReadOnlyException(); } public bool包含(KeyValuePair项) { 返回_dictionary.Contains(项); } public void CopyTo(KeyValuePair[]数组,int-arrayIndex) { _CopyTo(数组,arrayIndex); } 公共整数计数 { 获取{return\u dictionary.Count;} } 公共图书馆是只读的 { 获取{return true;} } 布尔ICollection.Remove(KeyValuePair项) { 抛出ReadOnlyException(); } #端区 #区域可数成员 公共IEnumerator GetEnumerator() { 返回_dictionary.GetEnumerator(); } #端区 #第一区
    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        private readonly IDictionary<TKey, TValue> _dictionary;
    
        public ReadOnlyDictionary()
        {
            _dictionary = new Dictionary<TKey, TValue>();
        }
    
        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        {
            _dictionary = dictionary;
        }
    
        #region IDictionary<TKey,TValue> Members
    
        void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
        {
            throw ReadOnlyException();
        }
    
        public bool ContainsKey(TKey key)
        {
            return _dictionary.ContainsKey(key);
        }
    
        public ICollection<TKey> Keys
        {
            get { return _dictionary.Keys; }
        }
    
        bool IDictionary<TKey, TValue>.Remove(TKey key)
        {
            throw ReadOnlyException();
        }
    
        public bool TryGetValue(TKey key, out TValue value)
        {
            return _dictionary.TryGetValue(key, out value);
        }
    
        public ICollection<TValue> Values
        {
            get { return _dictionary.Values; }
        }
    
        public TValue this[TKey key]
        {
            get
            {
                return _dictionary[key];
            }
        }
    
        TValue IDictionary<TKey, TValue>.this[TKey key]
        {
            get
            {
                return this[key];
            }
            set
            {
                throw ReadOnlyException();
            }
        }
    
        #endregion
    
        #region ICollection<KeyValuePair<TKey,TValue>> Members
    
        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
        {
            throw ReadOnlyException();
        }
    
        void ICollection<KeyValuePair<TKey, TValue>>.Clear()
        {
            throw ReadOnlyException();
        }
    
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _dictionary.Contains(item);
        }
    
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            _dictionary.CopyTo(array, arrayIndex);
        }
    
        public int Count
        {
            get { return _dictionary.Count; }
        }
    
        public bool IsReadOnly
        {
            get { return true; }
        }
    
        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
        {
            throw ReadOnlyException();
        }
    
        #endregion
    
        #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _dictionary.GetEnumerator();
        }
    
        #endregion
    
        #region IEnumerable Members
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        #endregion
    
        private static Exception ReadOnlyException()
        {
            return new NotSupportedException("This dictionary is read-only");
        }
    }
    
    public interface IReadOnlyDictionary<TKey, TValue> : IEnumerable
    {
        bool ContainsKey(TKey key);
        ICollection<TKey> Keys { get; }
        ICollection<TValue> Values { get; }
        int Count { get; }
        bool TryGetValue(TKey key, out TValue value);
        TValue this[TKey key] { get; }
        bool Contains(KeyValuePair<TKey, TValue> item);
        void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex);
        IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
    }
    
    public class ReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
    {
        readonly IDictionary<TKey, TValue> _dictionary;
        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        {
            _dictionary = dictionary;
        }
        public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
        public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
        public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); }
        public ICollection<TValue> Values { get { return _dictionary.Values; } }
        public TValue this[TKey key] { get { return _dictionary[key]; } }
        public bool Contains(KeyValuePair<TKey, TValue> item) { return _dictionary.Contains(item); }
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { _dictionary.CopyTo(array, arrayIndex); }
        public int Count { get { return _dictionary.Count; } }
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dictionary.GetEnumerator(); }
        IEnumerator IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); }
    }
    
    ReadOnlyDictionary<int, int> test = new ReadOnlyDictionary<int,int>(new Dictionary<int, int> { { 1, 1} });
    test.Add(2, 1);  //CS1061
    
    error CS1061: 'System.Collections.Generic.ReadOnlyDictionary<int,int>' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument 
    
    namespace System.Collections.Generic
    {
        public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
        {
            const string READ_ONLY_ERROR_MESSAGE = "This dictionary is read-only";
    
            protected IDictionary<TKey, TValue> _Dictionary;
    
            public ReadOnlyDictionary()
            {
                _Dictionary = new Dictionary<TKey, TValue>();
            }
    
            public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
            {
                _Dictionary = dictionary;
            }
    
            public bool ContainsKey(TKey key)
            {
                return _Dictionary.ContainsKey(key);
            }
    
            public ICollection<TKey> Keys
            {
                get { return _Dictionary.Keys; }
            }
    
            public bool TryGetValue(TKey key, out TValue value)
            {
                return _Dictionary.TryGetValue(key, out value);
            }
    
            public ICollection<TValue> Values
            {
                get { return _Dictionary.Values; }
            }
    
            public TValue this[TKey key]
            {
                get { return _Dictionary[key]; }
                set { throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE); }
            }
    
            public bool Contains(KeyValuePair<TKey, TValue> item)
            {
                return _Dictionary.Contains(item);
            }
    
            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
            {
                _Dictionary.CopyTo(array, arrayIndex);
            }
    
            public int Count
            {
                get { return _Dictionary.Count; }
            }
    
            public bool IsReadOnly
            {
                get { return true; }
            }
    
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
            {
                return _Dictionary.GetEnumerator();
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return (_Dictionary as IEnumerable).GetEnumerator();
            }
    
            void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
            {
                throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
            }
    
            bool IDictionary<TKey, TValue>.Remove(TKey key)
            {
                throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
            }
    
            void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
            {
                throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
            }
    
            void ICollection<KeyValuePair<TKey, TValue>>.Clear()
            {
                throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
            }
    
            bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
            {
                throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
            }
        }
    }
    
    public class ReadOnlyException : Exception
    {
    }
    
    public class ReadOnlyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
            : base(dictionary) { }
    
        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
            : base(dictionary, comparer) { }
    
        //The following four constructors don't make sense for a read-only dictionary
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public ReadOnlyDictionary() { throw new ReadOnlyException(); }
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public ReadOnlyDictionary(IEqualityComparer<TKey> comparer) { throw new ReadOnlyException(); }
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public ReadOnlyDictionary(int capacity) { throw new ReadOnlyException(); }
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public ReadOnlyDictionary(int capacity, IEqualityComparer<TKey> comparer) { throw new ReadOnlyException(); }
    
    
        //Use hiding to override the behavior of the following four members
        public new TValue this[TKey key]
        {
            get { return base[key]; }
            //The lack of a set accessor hides the Dictionary.this[] setter
        }
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public new void Add(TKey key, TValue value) { throw new ReadOnlyException(); }
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public new void Clear() { throw new ReadOnlyException(); }
    
        [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
        public new bool Remove(TKey key) { throw new ReadOnlyException(); }
    }
    
    var dict = new Dictionary<int, string>
    {
        { 1, "one" },
        { 2, "two" },
        { 3, "three" },
    };
    
    var rodict = new ReadOnlyDictionary<int, string>(dict);
    var rwdict = rodict as Dictionary<int, string>;
    rwdict.Add(4, "four");
    
    foreach (var item in rodict)
    {
        Console.WriteLine("{0}, {1}", item.Key, item.Value);
    }