我有一个
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());
在此处了解有关不可变集合的更多信息.
我遇到了同样的问题。我通过以下方式解决了它。
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");
这有积极的效果,你
也许这会对某人有所帮助。
首先,您必须创建一个具有所需内容类型的新词典:
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.
换句话说,
TValue
中的
Dictionary
不是协变的。从面向对象的角度来看,协变应该在字典的只读版本中是可能的,但是.NET框架中存在遗留问题阻止了这一点(参见this中以“UPDATE”开头的部分问题了解详情)。
如果你想返回一个只读字典,但仍然能够在你的类中改变字典和列表,你可以使用转换来取回列表类型。
这个例子有点做作,但展示了它是如何工作的。
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 将是最佳选择。
不是直接回答问题,而是.Net 8介绍FrozenDictionary.
新的
System.Collections.Frozen
命名空间包括集合类型 FrozenDictionary<TKey,TValue>
和 FrozenSet<T>
。一旦创建了集合,这些类型就不允许对键和值进行任何更改。该要求允许更快的读取操作(例如,TryGetValue()
)。这些类型对于首次使用时填充然后在长期服务期间持续存在的集合特别有用,例如:
https://msdn.microsoft.com/en-us/library/acdd6hb7.aspx
您可以使用它来将对象公开为只读。
你也可以使用属性获取;放;并且只允许公开。
但Matias的回答似乎更合适。