核心C#库中是否有任何内置内容可以给我提供一个不可变的字典?
类似于Java的一些内容:
Collections.unmodifiableMap(myMap);
仅想澄清的是,我并不希望停止更改字典中的键/值本身,而是希望停止更改字典的结构。我需要一些东西,如果调用IDictionary的任何mutator方法(Add,Remove,Clear
)会迅速且明确地失败。
核心C#库中是否有任何内置内容可以给我提供一个不可变的字典?
类似于Java的一些内容:
Collections.unmodifiableMap(myMap);
仅想澄清的是,我并不希望停止更改字典中的键/值本身,而是希望停止更改字典的结构。我需要一些东西,如果调用IDictionary的任何mutator方法(Add,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();
}
}
backingDict
的人可以修改集合)。另一方面,不可变集合则保证不会被任何人修改。 - Joren.NET 4.5发布后,出现了一个新的ReadOnlyDictionary类。你只需将IDictionary
传递给构造函数即可创建不可变字典。
这里有一个有用的扩展方法,可用于简化创建只读字典的过程。
我知道这是一个非常老的问题,但是在2020年我某种方式找到了它,因此我认为值得注意的是,现在有一种创建不可变字典的方法:
用法:
using System.Collections.Immutable;
public MyClass {
private Dictionary<KeyType, ValueType> myDictionary;
public ImmutableDictionary<KeyType, ValueType> GetImmutable()
{
return myDictionary.ToImmutableDictionary();
}
}
在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"}
};
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;
我不这么认为。有一种方法可以创建只读列表和只读集合,但我不认为内置了只读字典。System.ServiceModel有一个ReadOnlyDictinoary实现,但它是内部的。不过,使用反射器很容易复制它,或者从头开始创建自己的只读字典。它基本上包装了一个字典,并在调用修改器时抛出异常。
相反,创建一个域对象,其接口不提供任何修改包装的字典的方法。而是提供所需的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...};
}
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");
ReadOnlyDictionary<TKey,TValue>
,与自 .Net 2.0 起就存在的ReadOnlyCollection<T>
并列。详情请参考 http://msdn.microsoft.com/en-us/magazine/jj133817.aspx 。 - Gordon Gustafson