使字典只能在C#中读取

时间:2016-08-22 18:38:17

标签: c# collections covariance

我有一个Dictionary<string, List<string>>,并希望将该成员公开为只读。我看到我可以将其作为IReadOnlyDictionary<string, List<string>>返回,但我无法弄清楚如何将其作为IReadOnlyDictionary<string, IReadOnlyList<string>>返回。

有办法做到这一点吗?在c ++中,我只是使用const,但C#没有。

请注意,在这种情况下简单地使用IReadOnlyDictionary没有帮助,因为我希望只读取值。似乎唯一的方法是构建另一个IReadOnlyDictionary,并向它们添加IReadOnlyList。

我不会兴奋的另一个选择是创建实现接口IReadOnlyDictionary&gt;的包装器,并让它保存原始实例的副本,但这似乎有点过分了。

6 个答案:

答案 0 :(得分:13)

将整个字典引用转换为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 package添加到您的解决方案中,然后您就可以使用它们了:

// ImmutableDictionary<string, ImmutableList<string>>
var immutableDict = dict.ToImmutableDictionary(pair => pair.Key, pair => pair.Value.ToImmutableList());

详细了解Immutable Collections here

答案 1 :(得分:3)

鉴于您专门寻找只读Dictionary<string, List<string>>这一事实,您基本上正在寻找Lookup

Dictionary对象的扩展名为ToLookup()

答案 2 :(得分:1)

首先,您必须创建一个包含所需内容类型的新词典:

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.

换句话说,TValue is not covariant中的Dictionary。从面向对象的角度来看,协方差应该在字典的只读版本中是可能的,但是在.NET框架中存在遗留问题阻止了这一点(参见以“更新“this question以获取详细信息。”

答案 3 :(得分:1)

我遇到了同样的问题。我通过以下方式解决了它。

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
  • 无法将其转换为字典
  • 无法将其投射到列表中
  • 让您的ReadOnlyDictionary始终保持最新状态

也许这会帮助某人。

答案 4 :(得分:0)

如果您想要返回一个只读字典,但仍然能够改变您的类中的字典和列表,您可以使用强制转换来获取列表类型。

这个例子有点人为,但展示了它是如何工作的。

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将是最佳选择。

答案 5 :(得分:-1)

https://msdn.microsoft.com/en-us/library/acdd6hb7.aspx

您可以使用它将对象公开为只读。

你也可以使用属性get;组;并且只允许公开。

但Matias的答案似乎更合适。