Vb.net 为什么重载的私有共享函数在从同一类中的共享函数调用时不可访问

Vb.net 为什么重载的私有共享函数在从同一类中的共享函数调用时不可访问,vb.net,Vb.net,遇到了一些我觉得有趣的事情,我希望得到一个解释 编辑 这个问题的答案并不意味着应该采取什么措施来解决它。我知道修复方法。我想解释一下为什么编译器会这样做。在这种情况下,是否不考虑私有功能 问题 我有一个类,它有一个名为WhatIs的公共共享(静态)函数。WhatIs接受具有对象集合的参数。代码迭代此集合并调用WhatIs函数,该函数具有与对象类型匹配的参数 执行时,会引发InvalidCastException异常,因为执行尝试调用启动该异常的WhatIs函数,而不是所提供类型的函数 这很奇怪,

遇到了一些我觉得有趣的事情,我希望得到一个解释

编辑

这个问题的答案并不意味着应该采取什么措施来解决它。我知道修复方法。我想解释一下为什么编译器会这样做。在这种情况下,是否不考虑私有功能

问题

我有一个类,它有一个名为WhatIs的公共共享(静态)函数。WhatIs接受具有对象集合的参数。代码迭代此集合并调用WhatIs函数,该函数具有与对象类型匹配的参数

执行时,会引发InvalidCastException异常,因为执行尝试调用启动该异常的WhatIs函数,而不是所提供类型的函数

这很奇怪,但让我感到奇怪的是,当您将私有共享函数更改为公共共享时,它就可以正常工作了

更奇怪的是,当您显式强制转换对象时,即使函数是私有的,它也会工作

什么?!请有人解释一下

代码

Private Function ShowMe(data As Integer) As String
    Return data.ToString
End Function

Private Function ShowMe(data As String) As String
    Return data
End Function

Private Function ShowMe(data As Double) As String
    Return data.ToString
End Function

Dim bla As New List(Of Object)
勇气:

检验


重新运行测试,您知道吗,它是有效的。首先,看起来您已经打开了隐式转换。这是问题的开始。其次,您将
家具
定义为
列表(对象)
。您对
WhatIs
的第一次调用成功。编译器在遍历
thing.Furniture
时传递它认为简单的
对象
时,正在对使用哪个重载进行最佳猜测,并确定
WhatIs
方法的公共静态版本是最合适的。然后,它尝试将
对象
隐式转换为
房屋
,但不可避免地失败

为什么铸造工作?因为在确定使用哪种重载时,需要进行猜测工作

这个故事的寓意是:不要让编译器猜。隐式转换可能导致棘手的错误

编辑:为什么编译器看不到其他重载函数

编译器必须在编译时确定要使用的正确重载。它不会等到运行时才确定要使用哪个重载,因此没有检查对象类型以确定最合适的重载的特权

由于编译器只知道
furniture
是一个
列表(对象)
,从技术上讲(启用隐式转换),所有三个重载都被认为是“适当的”,但编译器必须选择一个。它对可能的过载候选项进行排序,并在
私有
版本之前选择
公共
版本

  • 始终使用

    选项严格限制在

  • 您无法通过添加名称相同的方法(仅使用不同的参数类型)使其更加灵活

  • 更新

    Private Function ShowMe(data As Integer) As String
        Return data.ToString
    End Function
    
    Private Function ShowMe(data As String) As String
        Return data
    End Function
    
    Private Function ShowMe(data As Double) As String
        Return data.ToString
    End Function
    
    Dim bla As New List(Of Object)
    
    如果你打电话

        bla.Add(12)
        bla.Add("hi")
        bla.Add(1.2)
        Dim text As String
        text = ShowMe(bla(0))
        text = ShowMe(bla(1))
        text = ShowMe(bla(2))
    
    然后编译器总是抱怨正确的方法不存在,因为正确的方法不是通过检查类型来选择的,而是通过定义来选择的,容器是为该类型定义的

    Private Function ShowMe(data As Object) As String
        Return data.ToString
    End Function
    
    这将为所有整数、双精度和字符串调用。如果不可用,则使用一些方法进行某种自动转换。这就是为什么你可以把整数放在浮点数里,或者把数字放在字符串里

    一种方法是检查其类型并进行explizit类型转换

        For Each ele As Object In bla
            If TypeOf ele Is Integer Then
                text = ShowMe(CInt(ele))
            ElseIf TypeOf ele Is Double Then
                text = ShowMe(CDbl(ele))
            Else
                text = ShowMe(CStr(ele))
            End If
        Next
    

    但这还不是很干净。如果要访问所有对象都应支持的属性,请将它们放在容器中,并将类型定义为确保这些属性存在的类型。

    添加选项Strict On,然后定义所有家具都支持的接口,例如iFurniture,它要求对象定义一个字符串返回函数。请参阅对w.brian回答的评论(对象列表)是有意的。那才是真正的傻瓜的来源。通常我会说得更具体一些,但这是在现实世界中出现的,因为XSD生成了类,所以这可能是其他人会遇到的问题。我应该补充一点,我知道有一些简单的修复方法,比如interaces/抽象类。这意味着更多的是,为什么编译器在这个场景中会这样做?我已经更新了我的答案。编译器在编译时而不是运行时确定重载。在运行时,调试器知道它是椅子并不重要,到那时,必须使用的重载已经确定。Watch和debug将根据实际对象实例显示运行时已知的内容。重载解析在编译时根据参数的类型执行。在这种情况下,参数的类型是
    Object
    ,因此选择房子的公共方法被确定为最佳方法,仅仅因为它是公共的。w.brian-你最后一句评论+steven的为我澄清了这一点。我不喜欢第1部分的答案(只是因为它是公共的,GRRRR愚蠢的编译器!),但接受这个解释:)同意。这是出于理论目的。在pt 2上,相同的名称、不同的参数没有错,事实上这就是重载的原因,所以我不确定你的意思,重载没有错,但不幸的是,它不起作用,是通过检查给定参数的真实类型来正确选择fitting重载方法。请参阅回答中的更新,我会关注您。有趣的一点。由于所有函数都是私有的,因此不会使用任何函数。哈甚至不根据pub/private进行排名,只是在隐式转换时忽略privates。谢谢你给出了一个明确的答案。不完全是我想要的,但是+1因为你带来了很好的补充
        bla.Add(12)
        bla.Add("hi")
        bla.Add(1.2)
        Dim text As String
        text = ShowMe(bla(0))
        text = ShowMe(bla(1))
        text = ShowMe(bla(2))
    
    Private Function ShowMe(data As Object) As String
        Return data.ToString
    End Function
    
        For Each ele As Object In bla
            If TypeOf ele Is Integer Then
                text = ShowMe(CInt(ele))
            ElseIf TypeOf ele Is Double Then
                text = ShowMe(CDbl(ele))
            Else
                text = ShowMe(CStr(ele))
            End If
        Next