【问题标题】:Can't convert Dictionary<string, List<string>> to IReadOnlyDictionary<string, IReadOnlyCollection<string>>无法将 Dictionary<string, List<string>> 转换为 IReadOnlyDictionary<string, IReadOnlyCollection<string>>
【发布时间】:2021-10-13 07:00:39
【问题描述】:

谁能解释一下这个问题?

Dictionary<string, List<string>> x
  = new Dictionary<string, List<string>>();

IReadOnlyDictionary<string, IReadOnlyCollection<string>> y 
  = new Dictionary<string, IReadOnlyCollection<string>>();

y = x;  // CS0266: Cannot implicitly convert type...

【问题讨论】:

标签: c# dictionary type-conversion generic-type-parameters ireadonlydictionary


【解决方案1】:

您可以像这样接近您的目标:

Dictionary<string, List<string>> x = new Dictionary<string, List<string>>()
  {
    { "Foo", new List<string> {"A", "B", "C"} }
  };

IReadOnlyDictionary<string, ReadOnlyCollection<string>> y = 
    new ReadOnlyDictionary<string, ReadOnlyCollection<string>>(x.ToDictionary(k => k.Key, v => new ReadOnlyCollection<string>(v.Value)));
    
IReadOnlyCollection<string> foo = y["Foo"];

请注意,ReadOnlyCollection&lt;T&gt; 包含您的原始列表。它不复制元素。 ReadOnlyDictionary&lt;TKey, TValue&gt; 也一样。

【讨论】:

    【解决方案2】:

    IReadOnlyDictionary 的值不是covariant。这是为了围绕TryGetValue 方法提供类型安全。

    考虑这个例子:

    Dictionary<string, List<string>> x = new Dictionary<string, List<string>>
    {
        { "Key", new List<string>() }
    };
    
    IReadOnlyDictionary<string, IReadOnlyCollection<string>> y = new Dictionary<string, IReadOnlyCollection<string>>
    {
        { "Key", new System.ArraySegment<string>() } //This is allowed because an ArraySegment implements IReadOnlyCollection<string>
    };
    
    List<string> foo;
    x.TryGetValue("Key", out foo);
    foo.Add("Some string");
    

    最后三行适用于x,因为它的值是List&lt;string&gt;。如果将y 分配给x,它将不起作用,因为它的值不是List&lt;string&gt;,并且您不能在其上调用Add。这是行不通的:

    y.TryGetValue("Key", out foo); //Error
    

    这也不会:

    x = y;
    x.TryGetValue("Key", out foo); //Error
    

    因为它适用于x 而不适用于y,所以它们不是类型兼容的,因此不允许强制转换。

    【讨论】:

      【解决方案3】:

      这篇文章完美地描述了您在代码中遇到的情况。

      Click?

      Dictionary 能够实现 IReadOnlyDictionary,因为任何采用后者的代码都承诺不会修改字典,这是前者提供的功能的子集。

      但考虑另一个方向。您从 IReadOnlyDictionary 开始,然后尝试将其转换为常规 Dictionary。现在,你把之前承诺不会修改的东西,变成了可以修改的东西。

      显然,那是行不通的。

      此外,您不能只假设只读实现在修改时会抛出异常或某些东西(例如运行时安全,即使不是编译时安全),因为如您所知,您总是可以获得来自可变实现的只读接口。

      为了安全起见,您有两种选择:

      只需将整个字典内容复制到一个新对象中。 将只读对象包装在 IDictionary 实现中,如果您尝试修改它,该实现会引发异常。 请注意,后者实际上并没有为您提供您具体要求的内容。它很接近,但它不是 Dictionary 的实际实例。

      在复制方面,您有很多选择。就个人而言,我认为 ToDictionary() 本身就很好。但是如果你真的不喜欢冗长,你可以将它包装在一个扩展方法中:

      public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
          this IReadOnlyDictionary<TKey, TValue> dictionary)
      {
          return dictionary.ToDictionary(x => x.Key, y => y.Value);
      }
      

      【讨论】:

      • 这不是问题。这是不可能的,因为TValue 在IReadOnlyDictionary&lt;TKey, TValue&gt; 中是不变的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多