【问题标题】:why are overloaded private shared function not accessible when called from shared function in same class为什么从同一类中的共享函数调用时无法访问重载的私有共享函数
【发布时间】:2013-04-10 17:13:30
【问题描述】:

遇到了一些我觉得有趣的东西,希望得到解释。

编辑

这个问题并不是要回答应该做些什么来解决它。我知道修复。我想要解释为什么编译器会这样做。前任。在这种情况下是否不考虑私有函数?

问题

我有一个类,它有一个名为 WhatIs 的公共共享(静态)函数。 WhatIs 接受一个包含对象集合的参数。代码遍历这个集合并调用一个 WhatIs 函数,该函数的参数类型与对象是什么相匹配。

执行时,会抛出 InvalidCastException 异常,因为该执行试图调用启动它的 WhatIs 函数,而不是所提供类型的函数。

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

更奇怪的是,当您显式转换对象时,即使该函数是私有的,它也可以工作。

什么?!有人请解释一下

代码

胆量:

Public Class House
    Public Property Furniture As ICollection(Of Object)

    Public Sub New()
        Furniture = New List(Of Object)
    End Sub
End Class

Public Class Chair
    Public Property IsComfortable As Boolean
End Class

Public Class Table
    Public Seats As Integer
End Class

Public Class HouseExaminer
    Public Shared Function WhatIs(thing As House) As String
        Dim isA As String = "a house that contains "

        For Each item In thing.Furniture
            isA &= WhatIs(item)
        Next

        Return isA
    End Function

    Private Shared Function WhatIs(thing As Chair) As String
        Return "a " & If(thing.IsComfortable, "comfortable", "uncomfortable") & " chair "
    End Function

    Private Shared Function WhatIs(thing As Table) As String
        Return "a table that seats " & thing.Seats & " iguanas"
    End Function
End Class

测试

Imports System.Text
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports stuff

<TestClass()>
Public Class HouseExaminerTests

    <TestMethod()>
    Public Sub TestWhatIs()
        Dim given As New House()
        Dim expected As String
        Dim actual As String

        given.Furniture.Add(New Chair() With {.IsComfortable = True})
        given.Furniture.Add(New Table() With {.Seats = 4})

        expected = "a house that contains a comfortable chair a table that seats 4 iguanas"
        actual = HouseExaminer.WhatIs(given)

        Assert.Equals(expected, actual)
    End Sub
End Class

结果

调试测试,你会得到: 无效转换异常 方法调用失败,因为无法使用这些参数调用“公共共享函数 WhatIs(thing As stuff.House) As String”:

自变量匹配参数 'thing' 无法从 'Chair' 转换为 'House'。

这些更改使它可以工作,但为什么呢?!

公开

将 HouseExaminer 中的私有共享函数更改为公共,重新运行测试。剧透,它有效

显式转换对象

将它们改回私有然后替换

isA &= WhatIs(item)

If TypeOf item Is Chair Then isA &= WhatIs(CType(item, Chair))
If TypeOf item Is Table Then isA &= WhatIs(CType(item, Table))

重新运行测试,你知道什么,它有效

【问题讨论】:

  • 添加Option Strict On,然后定义一个所有家具都支持的接口,例如iFurniture,它需要对象定义一个字符串返回函数。
  • 查看 cmets 以响应 w.brian 的回答

标签: vb.net


【解决方案1】:

首先,您似乎开启了隐式转换。这就是问题的开始。其次,您将Furniture 定义为List(of Object)。您对WhatIs 的第一次呼叫成功了。编译器在传递 it 所认为的简单 Object 时对使用哪个重载进行了最佳猜测,因为它迭代了 thing.Furniture,并确定了 WhatIs 的公共静态版本方法是最合适的。然后它会尝试将Object 隐式转换为House,但不可避免地会失败。

为什么铸造有效?因为它在确定使用哪个重载时需要猜测。

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

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

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

由于编译器只知道furnitureList(Of Object),从技术上讲(启用隐式转换)所有三个重载都被认为是“适当的”,但编译器必须选择一个。它对可能的重载候选者进行排名,并在 private 之前选择 public 版本。

【讨论】:

  • List(of object) 是故意完成的。这就是真正的傻瓜的来源。通常我会更具体,但由于 XSD 生成的类,这在现实世界中出现了,所以它可能是其他人会遇到的。
  • 我应该补充一点,我知道有一些简单的修复方法,比如交互/抽象类。这意味着更多,为什么编译器会按照它在这种情况下的方式行事
  • 我已经更新了我的答案。编译器在编译时而不是运行时确定重载。在运行时调试器知道它是一把椅子并不重要,到那时,必须使用的重载已经确定。
  • 观察和调试显示的是基于实际对象实例在运行时已知的内容。重载解析是在编译时根据参数的类型执行的。在这种情况下,参数的类型是Object,因此仅仅因为它是公共的,就确定取房子的公共方法是最好的。
  • w.brian - 你最后一句评论 + steven's 为我解决了问题。我不喜欢这个答案(只是导致其公开,GRRRR 愚蠢的编译器!)但接受这个解释它:)
【解决方案2】:
  1. 始终使用

    选项严格开启

  2. 您无法通过添加名称相同的方法来使其更灵活,只是使用不同的参数类型。

更新

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

对于所有整数、双精度数和字符串都会调用此方法。如果它不可用,则使用一些可以进行某种自动转换的方法。这就是为什么您可以将整数放入浮点数中,或将数字放入字符串中。

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

    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

但这仍然不是那么干净。如果您想访问所有对象都应支持的属性,请将它们放入容器中并将类型定义为确保这些属性存在的东西。

【讨论】:

  • 第 1 点,同意。这样做是出于理论目的。在 pt 2 上,相同的名称,不同的参数没有任何问题,实际上这就是重载的原因,所以我不确定我是否明白你的意思
  • 重载并没有错,但不幸不起作用的是通过检查给定参数的真实类型来正确选择拟合重载方法。查看答案中的更新
  • 我跟着你。有趣的一点。由于所有功能都是私有的,因此不会使用任何功能。哈!甚至不根据 pub/private 进行排名,只是忽略隐式转换的 privates。感谢您整理出一个答案。不完全是我想要的,但是 +1 因为你带来了很好的补充
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多