在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>,并让它保存原始实例的副本,但这似乎是多余的。

在c#中使字典只读

就像将整个字典引用转换为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());

那么你可以返回新字典,因为IReadOnlyDictionaryDictionary的超类型。


你为什么要那样做?因为Dictionary<T, A>不是Dictionary<T, B>的超类型,所以即使 AB的超类型,也是如此。为什么?考虑下面的例子:

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的回答似乎更合适。