.Net继承和成员可见性的奇怪问题

bar*_*oyd 3 .net oop inheritance

我在VB.Net类库中遇到了一个问题,我将其大大简化为以下内容...

Public MustInherit Class TargetBase

End Class

Public Class TargetOne
    Inherits TargetBase
End Class

Public Class TargetTwo
    Inherits TargetBase
End Class

Public Class TargetManager
    Public Sub UpdateTargets(ByVal Targets As List(Of TargetBase))
        For Each objTarget As TargetBase In Targets
            UpdateTarget(objTarget)
        Next
    End Sub

    Private Sub UpdateTarget(ByVal Value As TargetOne)

    End Sub

    Private Sub UpdateTarget(ByVal Value As TargetTwo)

    End Sub
End Class
Run Code Online (Sandbox Code Playgroud)

由于行上的语法错误,这将无法编译UpdateTarget(objTarget)- 重载解析失败,因为没有缩小转换就无法调用可访问的'UpdateTarget'

所以我改变For-Each循环使用Object而不是TargetBase ...

For Each objTarget As Object In Targets
    UpdateTarget(objTarget)
Next
Run Code Online (Sandbox Code Playgroud)

这现在编译,但我得到一个运行时错误 - 未找到类型'TargetManager'上的公共成员'UpdateTarget'.

所以我采取了明显的下一步,使2 UpdateTarget()重载公共(而不是私有).

Public Sub UpdateTarget(ByVal Value As TargetOne)

End Sub

Public Sub UpdateTarget(ByVal Value As TargetTwo)

End Sub
Run Code Online (Sandbox Code Playgroud)

这现在有效!

我可以理解为什么将它更改为Object会起作用,但为什么当我只在同一个类中调用它们时,这些方法必须公开 - 我宁愿它们在这个类之外也不可用.

任何人都能解释一下吗?

在此先感谢(对不起这个问题的长度!)

另外 感谢迄今为止每个人的答案.我得到了解决方法(使UpdateTarget方法公共),使其工作.另一个解决方法是在调用UpdateTarget之前对objTarget进行TypeOf检查,然后再调用DirectCast,就像...

For Each objTarget As Object In Targets
    If TypeOf objTarget Is TargetOne Then
        UpdateTarget(DirectCast(objTarget, TargetOne))
    ElseIf TypeOf objTarget Is TargetTwo Then
        UpdateTarget(DirectCast(objTarget, TargetTwo))
    End If
Next
Run Code Online (Sandbox Code Playgroud)

这也有用 - 我发布了这个问题,因为我真的想了解为什么将UpdateTarget的可见性从Private更改为Public来摆脱运行时错误,这完全违背了我的理解!

Ada*_*rth 5

在我看来它无法决定使用哪种方法,因为您使用的是两种方法参数的基本类型.TargetOne/Two都是有效的TargetBases,因此两种方法看起来与分辨率引擎相同 - 这意味着它无法选择.

但是,我不知道为什么其他更改会使其工作...让我想一想,更新待定.

在C#中我没有遇到这个问题,因为你无法将TargetBase转发到TargetOne或TargetTwo ...它给出了不同的编译器错误 - 方法的参数无效,因为它不能隐式地将base转换为derived.您提到的第一个编译器错误基本上是VB.NET等效的.

我发现了这个链接,但我不确定它是用于VB还是VB.NET - 无论哪种方式,有趣的阅读:http: //msdn.microsoft.com/en-us/library/tb18a48w.aspx

这也可能与Option StrictVB.NET 2010中的和共同变化有关.本文有一些重载部分,可能证明有用:http: //msdn.microsoft.com/en-us/magazine/ee336029.aspx

更新:请注意,我不知道为什么它突然工作,这听起来像Jon Skeet或Eric Lippert.

更新2:我可以建议的一件事是针对每种情况(私有对公共/使用对象)编译应用程序并使用Reflector查看IL.基本上,寻找任何差异 - 可能是编译器正在为您添加一些内容 - 或者运行时能够根据当前类型确定正确的方法.

更新3:认为我明白了. 这句话来自以下链接:

"当一个对象被赋值给一个声明为特定对象类型的变量时,它就是早期绑定的."

http://visualbasic.about.com/od/usingvbnet/a/earlybind.htm

说当你指定TargetBase时,它是早期绑定和编译器抱怨.当你指定对象时,它是后期绑定的,运行时会在其私有链接时抱怨:

http://msdn.microsoft.com/en-us/library/h3xt2was(VS.80).aspx

因此,为您指定公共工程.运行时显然能够延迟绑定到正确的重载 - 这是VB.NET为您隐藏的后期绑定的一个很好的特性:-)