在c#中使字典只读
本文关键字:字典 只读 | 更新日期: 2023-09-27 18:03:40
我有一个Dictionary<string, List<string>>
,并希望将该成员公开为只读。我看到我可以将其作为IReadOnlyDictionary<string, List<string>>
返回,但我不知道如何将其作为IReadOnlyDictionary<string, IReadOnlyList<string>>
返回。
有办法做到这一点吗?在c++中,我只会使用const,但c#没有。
注意,在这种情况下,简单地使用IReadOnlyDictionary
没有帮助,因为我也希望这些值是只读的。看来唯一的方法就是建立另一个IReadOnlyDictionary,并将IReadOnlyList添加到其中。
另一个选项,我不会兴奋,将是创建包装器实现接口IReadOnlyDictionary>,并让它保存原始实例的副本,但这似乎是多余的。
就像将整个字典引用转换为IReadOnlyDictionary<string, IReadOnlyList<string>>
一样简单,因为Dictionary<TKey, TValue>
实现了IReadOnlyDictionary<TKey, TValue>
。
顺便说一句,你不能这样做,因为你希望List<string>
的值为IReadOnlyList<string>
。
你需要这样写:
var readOnlyDict = (IReadOnlyDictionary<string, IReadOnlyList<string>>)dict
.ToDictionary(pair => pair.Key, pair => pair.Value.AsReadOnly());
不变的字典
这只是一个建议,但如果你正在寻找不可变的字典,添加System.Collections.Immutable
NuGet包到你的解决方案,你将能够使用它们:
// ImmutableDictionary<string, ImmutableList<string>>
var immutableDict = dict
.ToImmutableDictionary(pair => pair.Key, pair => pair.Value.ToImmutableList());
考虑到您正在专门寻找只读Dictionary<string, List<string>>
的事实,您基本上正在寻找查找。
Dictionary对象有ToLookup()
扩展名
我遇到了同样的问题。我用下面的方法解决了它。
List<string> list = new List<string>();
Dictionary<string, IReadOnlyCollection<string>> dic = new Dictionary<string, IReadOnlyCollection<string>>();
IReadOnlyDictionary<string, IReadOnlyCollection<string>> dicRo = new ReadOnlyDictionary<string, IReadOnlyCollection<string>>(dic);
list.Add("Test1");
dic["T"] = list.AsReadOnly();
ist.Add("Test2");
这有积极的影响,你
- 仍然可以将项目添加到列表
- 仍然可以添加条目到字典
- 无法编辑ReadOnlyDictionary
- 无法编辑ReadOnlyCollection
- 不能强制转换成Dictionary
- 不能强制转换为List
- 让你的ReadOnlyDictionary总是最新的
首先,您必须创建一个包含所需内容类型的新字典:
var dicWithReadOnlyList = dic.ToDictionary(
kv => kv.Key,
kv => kv.Value.AsReadOnly());
那么你可以返回新字典,因为IReadOnlyDictionary
是Dictionary
的超类型。
你为什么要那样做?因为Dictionary<T, A>
不是Dictionary<T, B>
的超类型,所以即使 A
是B
的超类型,也是如此。为什么?考虑下面的例子:
var dic = new Dictionary<T, B>();
Dictionary<T, A> dic2 = dic; // Imagine this were possible...
dic2.Add(someT, someA); // ...then we'd have a type violation here, since
// dic2 = dic requires some B as the value.
也就是说,Dictionary
中的TValue
不协变。从面向对象的角度来看,协方差应该在只读版本的字典中是可能的,但是。net框架中的遗留问题阻止了这一点(详见问题中以"UPDATE"开头的部分)。
没有直接回答这个问题,但是。net 8引入了FrozenDictionary。
新的System.Collections.Frozen
命名空间包括FrozenDictionary<TKey,TValue>
和FrozenSet<T>
两个集合类型。一旦创建了集合,这些类型不允许对键和值进行任何更改。该需求允许更快的读取操作(例如,TryGetValue()
)。这些类型对于在第一次使用时填充,然后在长期服务期间持续保存的集合特别有用,例如:
如果您想返回一个只读字典,但仍然能够改变类中的字典和列表,您可以使用强制类型转换来返回列表类型。
这个例子有点做作,但展示了它是如何工作的。
public class MyClass
{
Dictionary<string, IReadOnlyList<string>> _dictionary;
public IReadOnlyDictionary<string, IReadOnlyList<string>> Dictionary { get { return _dictionary; } }
public MyClass()
{
_dictionary = new Dictionary<string, IReadOnlyList<string>>();
}
public void AddItem(string item)
{
IReadOnlyList<string> readOnlyList = null;
List<string> list = null;
if (!_dictionary.TryGetValue(item, out readOnlyList))
{
list = new List<string>();
_dictionary.Add(item, list);
}
else
list = readOnlyList as List<string>;
list.Add(item);
}
}
如果您的目标是使属性不可变,那么使用ReadOnlyDictionary将是最好的选择。
https://msdn.microsoft.com/en-us/library/acdd6hb7.aspx
您可以使用它将对象公开为只读。
你也可以使用属性get;设置;并且只允许get是公开的。
但Matias的回答似乎更合适。