Public Class A
Public Class B : Inherits A
Dim DictA As Dictionary(Of Integer, A)
Dim DictB As New Dictionary(Of Integer, B)
DictA = DictB
这不起作用,因为无法转换类型。这有可能吗?
答案 0 :(得分:4)
没有。您遇到了泛型差异问题,除了一些非常特殊的方法之外,.NET不支持这种问题。
原因如下:在你的最后一行之后,你有一个单独的字典,有两个“视图”。现在想象你写道:
DictA.Add(1, New A())
(如果我的VB略微关闭,请道歉。)在字典中插入了“非B”,但DictB认为所有值都是B的实例。
泛型的主要目的之一是在编译时捕获潜在的类型失败而不是执行时间 - 这意味着此代码应该无法编译,实际上它确实因为缺乏方差而正确。
当你习惯了正常的继承时,这有点违反直觉,但它确实有意义。一堆香蕉不仅仅是水果的集合 - 它是香蕉的集合。
Java使用来自调用方的通配符对此采取了一些不同的立场 - 例如,它可以让你看到DictB字典的“添加”方面,因为你添加到DictB的任何东西都可以在DictA中使用。 Java的泛型与.NET泛型非常不同......
答案 1 :(得分:0)
这是静态类型系统的一个有趣且非常复杂的方面。 您正在寻找的术语是协方差和逆变。
c#语言将在4.0中的Generic类型的某些操作中获得此功能,但形式有限。
你已经在某种程度上以
的形式拥有它object[] x = new string[1];
允许这样做是因为对数组进行了协变处理,这意味着您可以执行以下操作:
x[0] = new object();
会在运行时抛出异常。你看到同样适用于你的词典......
c#4.0规范仍然是非最终版本,因此可能会有所变化,但对于一些讨论和解释,请参阅this question
答案 2 :(得分:0)
不幸的是没有。这是已知的协方差/逆变支持的缺失。 CLR支持它,但C#和VB.Net的编译器不支持。
C#(4.0)的下一个版本现在确实支持它,但不确定vb.net。 此外,使用System.Linq,其中一个扩展方法是Cast(),它允许您从一种类型的集合转换为另一种类型。但是它仍然会返回IEnumerable,所以你需要稍微操作一下,但我认为键值类型比只有一个泛型类型的集合更难。