当值类型可以相互强制转换时,为什么不能将一种值类型的字典强制转换为另一种值类型的字典?



可能的重复项:
在 C# 中,为什么不能将 List 对象存储在 List 变量

为什么以下方法不起作用?

List<string> castMe = new List<string>();
IEnumerable<string> getFromCast  = (IEnumerable<string>)castMe; // allowed.
Dictionary<int, List<string>> castMeDict = new Dictionary<int, List<string>>();
Dictionary<int, IEnumerable<string>> getFromDict = (Dictionary<int, IEnumerable<string>>)castMeDict;  // Not allowed

这是Dictionary铸造机制的缺陷,还是我认为应该允许这样做?

谢谢。

这是字典转换机制中的缺陷,还是我认为应该允许这样做?

在你的思维中。您期望字典在其转换中应该是协变的。他们不是,原因如下。假设他们是,并推断出可能出错的地方:

Dictionary<int, List<string>> castMeDict = 
    new Dictionary<int, List<string>>();
Dictionary<int, IEnumerable<string>> getFromDict = 
    (Dictionary<int, IEnumerable<string>>)castMeDict;
castMeDict[123] = new List<string>();
IEnumerable<string> strings = getFromDict[123]; // No problem!
getFromDict[123] = new string[] { "hello" }; // Big problem!

字符串数组可转换为IEnumerable<string>但不能转换为List<string>。您只需将不是字符串列表的内容放入只能接受字符串列表的字典中。

在 C# 中,如果满足以下所有条件,泛型类型可以是协变或逆变:

  • 你使用的是 C# 4 或更高版本。
  • 不同的泛型类型是接口或委托。
  • 方差可证明是类型安全的。(C# 规范描述了我们用于确定方差安全性的规则。C# 4.0 版本文档文件可以下载 [这里]。请参阅第 23.5 节。
  • 变化的类型参数都是引用类型。
  • 该类型已被特别标记为对差异安全。

字典不满足这些条件中的大多数 - 它不是接口或委托,它不是可证明的安全,并且类型未标记为对方差安全。因此,字典没有差异。

相比之下,IEnumerable<T>确实满足所有这些条件。可以在 C# 4 中将IEnumerable<string>转换为IEnumerable<object>

如果您对方差主题感兴趣,请考虑阅读我关于该主题的二十几篇文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

研究逆变和协方差。有关为什么这种情况可能是一件坏事的特定示例,请查看Jon Skeet的答案。

想想如果允许会发生什么,然后你做了:

getFromDict.Add(34, new HashSet<string>);

这是完全允许的; HashSet<string>实现IEnumerable<string>,可以作为值添加到Dictionary<int, IEnumerable<string>>。它不能被添加到一个Dictionary<int, List<string>>,而这个对象才是真正的。

如果你想把它用作只读IDictionary<int, IEnumerable<string>>那么你可以从一个包装类中获得很好的效率,该包装类在运行时强制转换为IEnumerable<string>

否则,您需要将值复制到新Dictionary<int, IEnumerable<string>>中。

相关内容

  • 没有找到相关文章

最新更新