为什么vb.net拒绝将嵌套协变接口赋值为“模糊”

时间:2012-12-10 17:20:16

标签: vb.net compiler-errors covariance ambiguity

在代码中:

Interface ISelf(Of Out TMe)
End Interface
Class SomeBase
    Implements ISelf(Of SomeBase)
End Class
Class SomeDerived
    Inherits SomeBase
    Implements ISelf(Of SomeDerived)
End Class
Module ISelfTester
    Sub TestISelf()
        Dim z7 As New SomeDerived
        Dim z8 As ISelf(Of SomeDerived)
        Dim z9 As ISelf(Of ISelf(Of SomeDerived))
        z8 = z7
        z9 = z8
        z9 = z7 ' Why is this illegal?
    End Sub
End Module

直接从Z7到Z9的分配产生消息“错误13选项Strict On不允许从'wokka.SomeDerived'到'wokka.ISelf(of Wokka.ISelf(Of wokka.SomeDerived))的隐式转换''因为转换是模棱两可的。“那个分配怎么比Z7到Z8,或Z8到Z9的分配更模糊?据我所知,所有三个赋值都必须是表示式保留转换,这意味着所有三个赋值都必须简单地存储与Z7相同的对象的引用。

我可以理解,如果我尝试将SomeDerived的实例分配给类型为ISelf(Of ISelf(Of SomeBase))的引用,则尝试访问该接口的成员可能会产生{{1}的实现}或SomeBase;如果成员是一个返回类型为SomeDerived的方法,我可以理解这种歧义可能导致编译失败(因为编译器不知道返回类型是什么)。但是,我很困惑,为什么仅仅因为“模糊性”而仅仅尝试分配引用失败,因为赋值不能被解释为除了直接存储对引用类型变量的引用之外的任何东西?

BTW,预期用途是TMe包含ISelf(Of T)类型的只读属性Self,其预期实现为T [a在每种情况下保持代表性的转换;我想我应该为Return This添加一个类约束,但它不会影响原始问题]。如果有一个人有兴趣实施的各种类TMe,那么应该可以利用ISelf(Of theirOwnTypes)的协方差来促进一些本来很困难的事情[例如}如果每个类对该实现感兴趣ISelfIMoe和/或ILarry等,还会实现相应的类ICurly,ISelfAndLarry(Of ItsOwnType),以及/或ISelfAndCurly(OfOwnType)ISelfAndMoe(Of ItsOwnType) ISelfAndMoe(IselfAndLarry(Of ICurly))param , etc. then one can accept a parameter type which is known to implement any combination of those interfaces e.g. param . Given that declaration, IMoe would implement param.Self , and ILarry {{ 1}} param.Self.Self would implement ICurly , and param would implement ISelfAndCurly(Of IMoe). Further, if the class implements the expected pattern, one could cast ILarry`(如果某个实现做了意外的事情,这样的演员可能会失败,但是如果对象的类遵循预期的模式,则应该成功。)

2 个答案:

答案 0 :(得分:4)

Option Strict On告诉编译器忽略引用隐式转换的简单引用。这是隐含的,因为z9被允许为SomeBase(Of SomeBase(Of SomeDerived)并且因为SomeDerived可以替换为SomeBase,所以编译器不确定你的意思。但是因为你在z8中明确地说它是ISelf(of SomeDerived),所以没有任何猜测。我怀疑你是否将z9改为ISelf(Of SomeDerived(Of SomeDerived),这种歧义可能会消失。

然而,作为一种观点,这种嵌套变得非常混乱,因为它堆叠在自身上并且可能成为维护的噩梦。

答案 1 :(得分:0)

我也觉得这很难理解。如果是这样的话:

Dim y9 As ISelf(Of ISelf(Of SomeBase))
y9 = z7

SomeDerivedISelf(Of ISelf(Of SomeBase))想象很多“路线”会更容易。

明确地看一下这个问题的例子:

SomeDerived "is a" ISelf(Of SomeDerived)

通过声明。从这里开始,使用协方差,可以得到:

ISelf(Of SomeDerived) "is a" ISelf(Of
                                      ISelf(Of SomeDerived)
                                                           )

但是,从第一个“方程式”到这个方程式有多种方法吗?一种方法似乎是将第一个方程插入到自身中,当然使用协方差。另一种方法可能是第一个等式中ISelf(Of ...)两侧的苹果"is a",然后使用某种传递性将原始方程与结果相结合。

我真的不确定这些是不同的方式。这里是否存在某种相关性,如抽象(形式)数学方程式:

(a·a)*x  =  a*(a*x)

也许我没有意义,这只是VB.NET编译器中的一个错误。如果从示例中删除基类SomeBase会发生什么?这种行为是否仍然存在?

another question on errors with contravariance声称VB.NET过于严格。但也许最好比too loose like C# seems to be过于严格。