为什么默认属性在删除项目时访问setter

时间:2018-06-12 18:57:32

标签: vb.net visual-studio-2017

在下面的代码中,当尝试从Cases列表中删除项目时,代码在Setter中断开,索引超出范围。在VisualStudio 2017中运行调试器时,它成功通过Remove()函数并删除最后一项,但在返回Main()后,它将在Setter上中断,并且调用堆栈表明它来自Remove调用。示例代码如下:

Sub Main()
    Dim Cases As Collection = New Collection()
    Dim caseIndex As Integer = 2
    Cases.Remove(Cases(caseIndex))
End Sub

Public Class Collection

    Public WithEvents Cases As List(Of CaseClass)

    Public Sub New()
        Cases = New List(Of CaseClass)()
        Cases.Add(New CaseClass)
        Cases.Add(New CaseClass)
        Cases.Add(New CaseClass)
    End Sub

    Default Public Property BeltCase(ByVal Index As Integer) As CaseClass
        Get
            Return Cases(Index)
        End Get
        Set(ByVal Value As CaseClass)
            Cases(Index) = Value
        End Set
    End Property

    Public Sub Remove(ByRef BeltCase As CaseClass)
        Cases.Remove(BeltCase)
    End Sub
End Class

Public Class CaseClass
    Public test As Int16
End Class

调用堆栈:

  

TestingVBBug.exe!TestingVBBug.Module1.Collection.set_BeltCase(Integer Index,TestingVBBug.Module1.CaseClass Value)Line 25 Basic     TestingVBBug.exe!TestingVBBug.Module1.Main()Line 6 Basic

那么我们为什么要经历塞特犬呢?为什么在我们退出删除功能后会发生这种情况?

1 个答案:

答案 0 :(得分:2)

问题是由您的Remove()方法引起的,也就是说,您有ByRef参数(出于某种原因)。使用ByRef时,对方法内参数所做的任何更改都必须反映到传递给方法的变量中。这通过将值重新分配原始变量来实现。

在你的情况下,它的工作原理如下:

  • 调用Remove()方法并将变量(Cases(caseIndex))传递给它。
  • 有些工作是在Remove()方法内完成的,可能或可能不包括更改参数BeltCase的值。
  • 参数BeltCase的值会重新分配给最初传递给方法(即Cases(caseIndex)的变量。
  • 作为上述步骤的结果,BeltCase属性的setter会被Index = 2调用,这会引发超出范围的异常,因为Cases(2)不存在(是去除)。

要确认,当您替换此行时,您可以看到此问题消失:

Cases.Remove(Cases(caseIndex))

..用:

Dim myCase As CaseClass = Cases(caseIndex)
Cases.Remove(myCase)

这样,您创建一个新变量,该变量引用相同的CaseClass对象,最重要避免调用Collection.BeltClase属性的setter。

但是,更好的解决方案是首先不要使用ByRef ,因为在这种情况下您似乎不需要它。因此,只需使用Public Sub Remove(ByVal BeltCase As CaseClass)代替。

点击this question查看有关ByValByRef的更多信息。

最后一件事,请不要给你的班级Collection打电话,因为看到你的项目的任何人都会感到非常困惑。