【发布时间】:2009-01-29 08:11:51
【问题描述】:
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
这不起作用,因为无法转换类型。这有可能吗?
【问题讨论】:
标签: vb.net dictionary
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
这不起作用,因为无法转换类型。这有可能吗?
【问题讨论】:
标签: vb.net dictionary
没有。您遇到了泛型差异的问题,除了一些非常特殊的方式外,.NET 不支持该问题。
原因如下:在你的最后一行之后,你有一个字典,上面有两个“视图”,有效。现在想象一下你写的:
DictA.Add(1, New A())
(抱歉,如果我的 VB 稍有偏差。)在字典中插入了一个“非 B”,但 DictB 认为所有值都是 B 的实例。
泛型的主要目的之一是在编译时而不是执行时捕获潜在的类型错误 - 这意味着该代码应该无法编译,而这正是由于缺乏方差而导致的。
当你习惯了普通的继承时,这有点违反直觉,但它确实是有道理的。一串香蕉不仅仅是水果的集合 - 它是香蕉的集合。
Java 在调用方使用通配符对此采取了一些不同的立场 - 例如,它会让您只看到字典中为 DictB 的“添加”端,因为您添加到 DictB 的任何内容在 DictA 中都可以。不过,Java 的泛型与 .NET 的泛型非常不同......
【讨论】:
这是静态类型系统的一个有趣且相当复杂的方面。 您正在寻找的术语是协变和逆变。
c# 语言将在 4.0 中对泛型类型进行某些类型的操作,但形式有所限制。
你已经在某种程度上拥有它
object[] x = new string[1];
这是允许的,因为数组是协变处理的,这意味着您可以执行以下操作:
x[0] = new object();
这会在运行时抛出异常。你知道这同样适用于你的字典吗...
c# 4.0 规范仍未最终确定,因此可能会发生变化,但有关一些讨论和解释,请参阅 this question
【讨论】:
很遗憾没有。这是已知的协方差/逆变支持的缺失。 CLR 支持它,但 C# 和 VB.Net 的编译器不支持。
下一个版本的 C# (4.0) 现在确实支持它,但不确定 vb.net。 此外,对于 System.Linq,其中一种扩展方法是 Cast(),它允许您从一种类型的集合转换为另一种类型。但是它仍然会返回 IEnumerable,因此您需要进行一些操作,但我认为键值类型会比只有一种泛型类型的集合更难。
【讨论】: