C#是否可以给我一个不变的字典?
核心图书馆中是否有什么可以给我不变的字典?
与Java类似的东西:
Collections.unmodifiableMap(myMap);
只是为了澄清一下,我并不是要阻止键/值本身被更改,而只是希望字典的结构不会停止更改。如果要调用IDictionary的任何mutator方法("添加,删除,清除"),我都希望它们能够快速响亮地失败。
解决方案
回答
我不这么认为。有一种创建只读列表和只读Collection的方法,但我认为没有内置的只读Dictionary。 System.ServiceModel具有ReadOnlyDictinoary实现,但其内部。不过,使用Reflector复制它,或者只是从头开始创建自己的复制,可能并不难。它基本上包装了Dictionary并在调用mutator时引发。
回答
据我所知,没有。但是也许我们可以从这些文章中复制一些代码(并学到很多):
CPart一中的不变性:不变性的种类
C第二部分中的不变性:一个简单的不变性栈
CPart三中的不变性:协变不变栈
CPart第四部分中的不变性:不变的队列
CPart六中的不变性:简单的二叉树
CPart七的不变性:有关二叉树的更多信息
CPart八的不变性:关于二叉树的更多内容
CPart九的不变性:学术性?加上我的AVL树实现
CPart 10中的不变性:双端队列
CPart 11中的不变性:工作中的双端队列
回答
没有"开箱即用"的方法。我们可以通过派生自己的Dictionary类并实现所需的限制来创建一个。
回答
一种解决方法是,从Dictionary中抛出一个新的KeyValuePair列表,以保持原始状态不变。
var dict = new Dictionary<string, string>(); dict.Add("Hello", "World"); dict.Add("The", "Quick"); dict.Add("Brown", "Fox"); var dictCopy = dict.Select( item => new KeyValuePair<string, string>(item.Key, item.Value)); // returns dictCopy;
这样,原始字典将不会被修改。
回答
不,但是包装器是微不足道的:
public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> { IDictionary<TKey, TValue> _dict; public ReadOnlyDictionary(IDictionary<TKey, TValue> backingDict) { _dict = backingDict; } public void Add(TKey key, TValue value) { throw new InvalidOperationException(); } public bool ContainsKey(TKey key) { return _dict.ContainsKey(key); } public ICollection<TKey> Keys { get { return _dict.Keys; } } public bool Remove(TKey key) { throw new InvalidOperationException(); } public bool TryGetValue(TKey key, out TValue value) { return _dict.TryGetValue(key, out value); } public ICollection<TValue> Values { get { return _dict.Values; } } public TValue this[TKey key] { get { return _dict[key]; } set { throw new InvalidOperationException(); } } public void Add(KeyValuePair<TKey, TValue> item) { throw new InvalidOperationException(); } public void Clear() { throw new InvalidOperationException(); } public bool Contains(KeyValuePair<TKey, TValue> item) { return _dict.Contains(item); } public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { _dict.CopyTo(array, arrayIndex); } public int Count { get { return _dict.Count; } } public bool IsReadOnly { get { return true; } } public bool Remove(KeyValuePair<TKey, TValue> item) { throw new InvalidOperationException(); } public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dict.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)_dict).GetEnumerator(); } }
显然,如果要允许修改值,可以更改上面的this []设置器。
回答
我发现了Chere的AVLTree的Inmutable(不是READONLY)实现。
AVL树在每个操作上的代价都是对数的(不是恒定的),但是仍然很快。
http://csharpfeeds.com/post/7512/Immutability_in_Csharp_Part_Nine_Academic_Plus_my_AVL_tree_implementation.aspx
回答
除了dbkk的答案外,我希望能够在首次创建ReadOnlyDictionary时使用对象初始化程序。我进行了以下修改:
private readonly int _finalCount; /// <summary> /// Takes a count of how many key-value pairs should be allowed. /// Dictionary can be modified to add up to that many pairs, but no /// pair can be modified or removed after it is added. Intended to be /// used with an object initializer. /// </summary> /// <param name="count"></param> public ReadOnlyDictionary(int count) { _dict = new SortedDictionary<TKey, TValue>(); _finalCount = count; } /// <summary> /// To allow object initializers, this will allow the dictionary to be /// added onto up to a certain number, specifically the count set in /// one of the constructors. /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void Add(TKey key, TValue value) { if (_dict.Keys.Count < _finalCount) { _dict.Add(key, value); } else { throw new InvalidOperationException( "Cannot add pair <" + key + ", " + value + "> because " + "maximum final count " + _finalCount + " has been reached" ); } }
现在,我可以像这样使用该类:
ReadOnlyDictionary<string, string> Fields = new ReadOnlyDictionary<string, string>(2) { {"hey", "now"}, {"you", "there"} };
回答
从Linq开始,存在一个通用接口ILookup。
在MSDN中阅读更多内容。
因此,要简单地获取不可变的字典,我们可以调用:
using System.Linq; // (...) var dictionary = new Dictionary<string, object>(); // (...) var read_only = dictionary.ToLookup(kv => kv.Key, kv => kv.Value);
回答
正如我在以下文章中所描述的,还有另一种选择:
http://www.softwarerockstar.com/2010/10/readonlydictionary-tkey-tvalue/
本质上,它是ReadOnlyCollection>的子类,它以更优雅的方式完成工作。从某种意义上讲,它具有优雅的编译时支持,使Dictionary成为只读,而不是抛出修改其中项目的方法的异常。