VB编译器不对Object进行隐式转换?

时间:2011-04-10 13:50:48

标签: c# .net vb.net compiler-construction casting

我最近报告了一个API的奇怪问题。基本上由于某种原因,当与VB代码一起使用时,VB编译器在尝试调用ToString()方法时不会对Object进行隐式转换。

以下是C#中的最小代码示例,其次是VB:

    Graph g = new Graph();
    g.LoadFromEmbeddedResource("VDS.RDF.Configuration.configuration.ttl");

    foreach (Triple t in g.Triples)
    {
        Console.WriteLine(t.Subject.ToString());
    }

上面的编译和运行正常,而下面没有:

    Dim g As Graph = New Graph()
    g.LoadFromEmbeddedResource("VDS.RDF.Configuration.configuration.ttl")

    For Each t As Triple In g.Triples
        Console.WriteLine(t.Subject.ToString())
    Next

第二个VB示例给出了以下编译器异常:

  

重载解析失败,因为没有   可访问的'ToString'接受此信息   争论的数量。

这似乎是由于我尝试写入控制台的属性t.Subject的类型明确定义了带有参数的ToString()方法。 VB编译器似乎期望使用其中一个并且似乎不会隐式地转换为Object并使用标准Object.ToString()方法而C#编译器会这样做。

有没有办法解决这个问题,例如一个VB编译器选项还是最好只是为了确保属性的类型(在这个例子中是一个接口)明确定义了一个非参数化的ToString()方法来确保与VB的兼容性?

修改

以下是Lucian要求的其他详细信息

  1. Graph是一个接口的实现,但实际上是无关紧要的,因为它是INode接口,t.Subject返回的类型是问题。
    INodeToString()定义了两个带参数
  2. 的重载
  3. 是的,这是编译时错误
  4. 不,我不使用hide-by-name,API全部用C#编写,所以如果我想
  5. 我就无法生成那种API

    请注意,我已经为接口添加了一个显式的非参数化ToString()重载,这已经解决了VB用户的问题。

2 个答案:

答案 0 :(得分:4)

RobV,我是VB规范的主角,所以我应该能够回答你的问题,但我需要澄清一下......

  • “Graph”上定义的重载是什么?如果你能制作一个独立的复制品,它会有所帮助。在不知道超载候选者的情况下很难解释重载行为:)

  • 你说它失败了“编译器异常”。那确实不存在。你的意思是“编译时错误”?还是“运行时例外”?

  • 需要检查的是,您是否依赖于任何“隐藏名称”与“隐藏信号”行为。 C#编译器只发出“hide-by-sig”API; VB编译器可以根据您是否使用“Shadows”关键字发出。

  • C#重载算法是逐级向上走继承层次结构,直到找到可能的匹配; VB重载算法是同时查看继承层次结构的所有级别,以查看哪个级别最匹配。这有点理论上的一点,但是对于你的问题有一个小小的自成一体的重复,我可以解释它在实践中意味着什么。

汉斯,我认为你的解释是正确的。您的代码给出了编译时错误“BC30455:没有为ToString的参数'mumble'指定参数”。但RobV经历过“重载解析失败,因为没有可访问的'ToString'接受这个数量的参数”。

答案 1 :(得分:2)

这是这种行为的重演。它还向您展示了使用CObj()进行强制转换的方法:

Module Module1
    Sub Main()
        Dim itf As IFoo = New CFoo()
        Console.WriteLine(itf.ToString())        '' Error BC30455
        Console.WriteLine(CObj(itf).ToString())  '' Okay
    End Sub
End Module

Interface IFoo
    Function ToString(ByVal mumble As Integer) As String
End Interface

Class CFoo
    Implements IFoo
    Function ToString1(ByVal mumble As Integer) As String Implements IFoo.ToString
        Return "foo"
    End Function
End Class

我认为这是在VB.NET语言规范第11.8.1章“重载方法解析”中注释的:

  

这条规则的理由是   如果一个程序是松散类型的   (也就是说,大多数或所有变量都是   声明为Object),重载   解决方案可能很难,因为   来自Object的所有转换都是   缩小。而不是拥有   过载分辨率在许多方面失败   情况(要求强类型   方法调用的参数),   分辨率适当超载   调用方法延迟到运行   时间。这允许松散类型   呼吁成功而无需额外的   管型。

     

这种不幸的副作用,   然而,是表演   迟到的电话需要施放   将目标调用到Object。如果是   一个结构值,这意味着   必须将值加到临时值。如果   最终调用的方法尝试   改变一个结构的领域,这个   一旦方法改变就会丢失   回报。

     

接口不包括在内   特殊规则,因为后期绑定   总是解决成员   运行时类或结构类型,   可能有不同的名称   他们的接口成员   实施

不确定。我将其音译为:VB.NET是一种松散类型的语言,其中许多对象引用通常是后期绑定的。这使得方法重载解决方案危险。