我在我的只读属性中返回对字典的引用.如何防止消费者更改我的数据?如果这是一个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
Jeff Yates.. 230
.NET Framework 4.5 BCL介绍ReadOnlyDictionary
(源代码).
由于.NET Framework 4.5 BCL不包含AsReadOnly
for词典,因此您需要编写自己的(如果需要).它将类似于以下内容,其简单性可能突出了它为什么不是.NET 4.5的优先级.
public static ReadOnlyDictionaryAsReadOnly ( this IDictionary dictionary) { return new ReadOnlyDictionary (dictionary); }
在.NET 4.5之前,没有.NET框架类包装Dictionary
类似于ReadOnlyCollection包装List.但是,创建一个并不困难.
这是一个例子 - 如果你是谷歌的ReadOnlyDictionary,还有很多其他的.
.NET Framework 4.5 BCL介绍ReadOnlyDictionary
(源代码).
由于.NET Framework 4.5 BCL不包含AsReadOnly
for词典,因此您需要编写自己的(如果需要).它将类似于以下内容,其简单性可能突出了它为什么不是.NET 4.5的优先级.
public static ReadOnlyDictionaryAsReadOnly ( this IDictionary dictionary) { return new ReadOnlyDictionary (dictionary); }
在.NET 4.5之前,没有.NET框架类包装Dictionary
类似于ReadOnlyCollection包装List.但是,创建一个并不困难.
这是一个例子 - 如果你是谷歌的ReadOnlyDictionary,还有很多其他的.
这是一个包装字典的简单实现:
public class ReadOnlyDictionary: IDictionary { private readonly IDictionary _dictionary; public ReadOnlyDictionary() { _dictionary = new Dictionary (); } public ReadOnlyDictionary(IDictionary dictionary) { _dictionary = dictionary; } #region IDictionary Members void IDictionary .Add(TKey key, TValue value) { throw ReadOnlyException(); } public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } public ICollection Keys { get { return _dictionary.Keys; } } bool IDictionary .Remove(TKey key) { throw ReadOnlyException(); } public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); } public ICollection Values { get { return _dictionary.Values; } } public TValue this[TKey key] { get { return _dictionary[key]; } } TValue IDictionary .this[TKey key] { get { return this[key]; } set { throw ReadOnlyException(); } } #endregion #region ICollection > Members void ICollection >.Add(KeyValuePair item) { throw ReadOnlyException(); } void ICollection >.Clear() { throw ReadOnlyException(); } public bool Contains(KeyValuePair item) { return _dictionary.Contains(item); } public void CopyTo(KeyValuePair [] array, int arrayIndex) { _dictionary.CopyTo(array, arrayIndex); } public int Count { get { return _dictionary.Count; } } public bool IsReadOnly { get { return true; } } bool ICollection >.Remove(KeyValuePair item) { throw ReadOnlyException(); } #endregion #region IEnumerable > Members public IEnumerator > 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"); } }
在最近的BUILD会议上宣布,自.NET 4.5以来,System.Collections.Generic.IReadOnlyDictionary
包含了界面.证明在这里(单声道)和这里(微软);)
不确定是否ReadOnlyDictionary
也包括在内,但至少在界面上创建一个暴露官方.NET通用接口的实现应该不难.
随意使用我的简单包装.它不实现IDictionary,因此它不必在运行时为可能更改字典的字典方法抛出异常.改变方法根本不存在.我为它创建了自己的界面,名为IReadOnlyDictionary.
public interface IReadOnlyDictionary: IEnumerable { bool ContainsKey(TKey key); ICollection Keys { get; } ICollection Values { get; } int Count { get; } bool TryGetValue(TKey key, out TValue value); TValue this[TKey key] { get; } bool Contains(KeyValuePair item); void CopyTo(KeyValuePair [] array, int arrayIndex); IEnumerator > GetEnumerator(); } public class ReadOnlyDictionary : IReadOnlyDictionary { readonly IDictionary _dictionary; public ReadOnlyDictionary(IDictionary dictionary) { _dictionary = dictionary; } public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } public ICollection Keys { get { return _dictionary.Keys; } } public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); } public ICollection Values { get { return _dictionary.Values; } } public TValue this[TKey key] { get { return _dictionary[key]; } } public bool Contains(KeyValuePair item) { return _dictionary.Contains(item); } public void CopyTo(KeyValuePair [] array, int arrayIndex) { _dictionary.CopyTo(array, arrayIndex); } public int Count { get { return _dictionary.Count; } } public IEnumerator > GetEnumerator() { return _dictionary.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); } }
IsReadOnly on IDictionary
继承自ICollection
(IDictionary
extends ICollection
as ICollection
).它不以任何方式使用或实现(实际上通过使用显式实现关联ICollection
成员来"隐藏" ).
我可以通过至少3种方式来解决问题:
按照建议实现自定义只读IDictionary
和包装/委托给内部字典
将ICollection
集合返回
为只读或
IEnumerable
取决于值的使用
使用复制构造函数克隆字典.ctor(IDictionary
并返回副本 - 这样用户可以随意使用它,并且它不会影响托管源字典的对象的状态.请注意,如果要克隆的字典包含引用类型(不是示例中所示的字符串),则需要"手动"复制并克隆引用类型.
作为旁白; 在暴露集合时,旨在暴露最小的可能接口 - 在示例中它应该是IDictionary,因为这允许您在不破坏类型公开的公共合同的情况下改变底层实现.
只读字典可以在某种程度上替换为Func
- 如果我只希望人们执行查找,我通常在API中使用它.它很简单,特别是,如果您愿意,更换后端很简单.但是,它没有提供密钥列表; 这是否重要取决于你在做什么.