当值类型可以相互转换时,为什么我不能将一个值类型的字典转换为另一个值类型的字典?
可能重复:
在C#中,为什么List 对象不能存储在List 变量中
以下为什么不工作?
List castMe = new List(); IEnumerable getFromCast = (IEnumerable)castMe; // allowed. Dictionary<int, List> castMeDict = new Dictionary<int, List>(); Dictionary<int, IEnumerable> getFromDict = (Dictionary<int, IEnumerable>)castMeDict; // Not allowed
这是Dictionary
铸造机制中的缺陷,还是我认为应该允许这样做?
谢谢。
这是字典铸造机制中的缺陷,还是我认为应该允许这样做?
在你的思考中。 您期望词典在转换中应该是协变的。 由于以下原因,它们不是。 假设它们是,并推断出可能出错的地方:
Dictionary> castMeDict = new Dictionary>(); Dictionary> getFromDict = (Dictionary>)castMeDict; castMeDict[123] = new List (); IEnumerable strings = getFromDict[123]; // No problem! getFromDict[123] = new string[] { "hello" }; // Big problem!
字符串数组可转换为IEnumerable
但不能转换为List
。 您只需将不是字符串列表的内容放入只能获取字符串列表的字典中。
在C#中,如果满足以下所有条件,则generics类型可以是协变的或逆变的:
- 你正在使用C#4或更好。
- 变化的generics类型是接口或委托。
- 方差可certificate是类型安全的。 (C#规范描述了我们用于确定方差安全性的规则.C#4.0版本doc文件可以在[这里]下载。请参阅第23.5节。)
- 变化的类型参数都是引用类型。
- 该类型已被特别标记为方差安全。
字典中不满足大多数条件 – 它不是接口或委托,它不可certificate是安全的,并且类型没有标记为方差安全。 因此,字典没有变化。
相比之下, IEnumerable
确实符合所有这些条件。 您可以在C#4中将IEnumerable
转换为IEnumerable
。
如果变化的主题让您感兴趣,请考虑阅读我关于该主题的二十多篇文章:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
研究逆向和协方差。 对于为什么这种情况可能是坏事的特定示例,请查看Jon Skeet的答案 。
想想如果它被允许会发生什么,然后你做了:
getFromDict.Add(34, new HashSet);
这是完全允许的; HashSet
实现IEnumerable
,可以作为值添加到Dictionary
。 它不能添加到Dictionary
,这就是该对象的真正含义。
如果你想将它作为只读IDictionary
那么你可以从一个转换为IEnumerable
的包装类中获得良好的效率。
否则,您需要将值复制到新的Dictionary
。