C#有没有给我一个不可变的字典的方法?

有什么内置的核心C#库,可以给我一个不可变的词典?

Java的一些东西:

Collections.unmodifiableMap(myMap); 

只是为了澄清,我不想阻止键/值本身被改变,只是字典的结构。 我想要的东西,如果任何IDictionary的mutator方法被调用( Add, Remove, ClearAdd, Remove, Clear快速失败的声音。

不,但是一个包装是相当微不足道的:

 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(); } } 

显然,如果您想允许修改值,您可以更改上面的[] setter。

据我所知,没有。 但可能是你可以从这些文章中复制一些代码(并学习很多):

C#中的不变性第一部分:不变性的种类
C#中的不变性第二部分:一个简单的不可变堆栈
C#中的不可变性第三部分:一个协变不变的栈
C#中的不变性:一个不可变的队列
C#中的不变性:一个简单的二叉树
C#中的不变性:更多关于二叉树
C#中的不变性:更多关于二叉树
C#中的不变性:学术吗? 加我的AVL树实现
C#中的不变性第10部分:双端队列
C#中的不变性第十一部分:一个工作的双端队列

随着.NET 4.5的发布,有一个新的ReadOnlyDictionary类。 您只需将IDictionary传递给构造函数即可创build不可变的字典。

这是一个有用的扩展方法,可以用来简化创build只读字典。

我不这么认为。 有一种方法来创build只读列表和只读集合,但我不认为有一个内置的只读字典。 System.ServiceModel有一个ReadOnlyDictinoary实现,但它的内部。 使用Reflector可能不会太难复制它,或者从头开始创build自己的应用程序。 它基本上包装一个字典,并在调用增变器时抛出。

添加到dbkk的答案 ,我想能够在首次创build我的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"} }; 

开源PowerCollections库包括一个只读字典包装器(以及几乎所有其他的只读包装器),可以通过Algorithms类的静态ReadOnly()方法访问。

一种解决方法可能是,从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; 

这样原来的字典将不会被修改。

“开箱即用”没有办法做到这一点。 你可以通过派生你自己的Dictionary类并实现你需要的限制来创build一个。

我在这里find了C#的AVLTree的Inmutable(不是READONLY)实现的实现。

AVL树在每个操作上都具有对数(而不是常数)的成本,但仍然很快。

http://csharpfeeds.com/post/7512/Immutability_in_Csharp_Part_Nine_Academic_Plus_my_AVL_tree_implementation.aspx

由于Linq,有一个通用的接口ILookup 。 阅读更多的MSDN 。

因此,要简单地获得不可变的字典,您可以调用:

 using System.Linq; // (...) var dictionary = new Dictionary<string, object>(); // (...) var read_only = dictionary.ToLookup(kv => kv.Key, kv => kv.Value); 

你可以尝试这样的事情:

 private readonly Dictionary<string, string> _someDictionary; public IEnumerable<KeyValuePair<string, string>> SomeDictionary { get { return _someDictionary; } } 

这将消除可变性问题,有利于您的调用者必须将其转换为他们自己的字典:

 foo.SomeDictionary.ToDictionary(kvp => kvp.Key); 

…或者在键上使用比较操作而不是索引查找,例如:

 foo.SomeDictionary.First(kvp => kvp.Key == "SomeKey"); 

总的来说,最好不要在任何字典中传递(如果你不需要的话)。

相反,创build一个域对象的接口,不提供任何修改字典(它包装)的方法。 而是提供所需的LookUp方法,通过键从字典中检索元素(比起字典,它更容易使用)。

 public interface IMyDomainObjectDictionary { IMyDomainObject GetMyDomainObject(string key); } internal class MyDomainObjectDictionary : IMyDomainObjectDictionary { public IDictionary<string, IMyDomainObject> _myDictionary { get; set; } public IMyDomainObject GetMyDomainObject(string key) {.._myDictionary .TryGetValue..etc...}; } 

还有另外一个select,我已经描述过了:

http://www.softwarerockstar.com/2010/10/readonlydictionary-tkey-tvalue/

本质上它是ReadOnlyCollection>的一个子类,它以更优雅的方式完成工作。 优点在于它具有编译时支持使Dictionary变为只读而不是从修改其中的项的方法抛出exception。