.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 onIDictionary
继承自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);
}