我长期以来一直在努力解决如何正确创建一个引用父类的类,以便在删除父对象时,所有子对象也被删除的问题。我将尝试在下面的示例中演示这一点。
假设我有一个像这样的简单子(monad)类“ClassChild”
Option Explicit
Private Type TChild
Field1 As String
End Type
Private this As TChild
Public Property Get Field1() As String
Field1 = this.Field1
End Property
Public Property Let Field1(Field1 As String)
this.Field1 = Field1
End Property
Private Sub Class_Initialize()
'
End Sub
Private Sub Class_Terminate()
Debug.Print "ClassChild_Terminate" & this.Field1
End Sub
为了收集此类的对象集合,我创建了一个父类“ClassParent”。
Option Explicit
Private Type TParent
Childs As Collection
End Type
Private this As TParent
Public Property Get Item(vItem As Variant) As ClassChild
Set Item = this.Childs(vItem)
End Property
Public Property Get Count() As Long
Count = this.Childs.Count
End Property
Public Property Get Childs() As Collection
Set Childs = this.Childs
End Property
Public Sub Add(Child As ClassChild)
this.Childs.Add Child, CStr(Child.Field1)
End Sub
Public Sub Remove(vItem As Variant)
this.Childs.Remove vItem
End Sub
Private Sub Class_Initialize()
Set this.Childs = New Collection
End Sub
Private Sub Class_Terminate()
Debug.Print "ClassParent_Terminate"
End Sub
通过这样的设计,一切正常,符合我的预期。
Sub testClassParent()
Dim Parent As ClassParent
Dim Child As ClassChild
Dim i As Integer
Set Parent = New ClassParent
For i = 1 To 5
Set Child = New ClassChild
Child.Field1 = CStr(i)
Parent.Add Child
Set Child = Nothing
Next
Set Parent = Nothing
End Sub
当父对象结束其生命时,所有子对象也会从内存中删除。
'Immediate
ClassChild_Terminate1
ClassChild_Terminate2
ClassChild_Terminate3
ClassChild_Terminate4
ClassChild_Terminate5
ClassParent_Terminate
当我希望 Child 类拥有对其父类的引用时,问题就出现了。因此,我向 ClassChild 和 ClassParent 添加几行
'ClassChild
Option Explicit
Private Type TChild
Field1 As String
Parent As ClassParent
End Type
Private this As TChild
Public Property Get Field1() As String
Field1 = this.Field1
End Property
Public Property Let Field1(Field1 As String)
this.Field1 = Field1
End Property
Public Property Get Parent() As ClassParent
Set Parent = this.Parent
End Property
Public Property Set Parent(Parent As ClassParent)
Set this.Parent = Parent
End Property
Private Sub Class_Initialize()
'
End Sub
Private Sub Class_Terminate()
Debug.Print "ClassChild_Terminate" & this.Field1
End Sub
'ClassParent
Option Explicit
Private Type TParent
Childs As Collection
End Type
Private this As TParent
Public Property Get Item(vItem As Variant) As ClassChild
Set Item = this.Childs(vItem)
End Property
Public Property Get Count() As Long
Count = this.Childs.Count
End Property
Public Property Get Childs() As Collection
Set Childs = this.Childs
End Property
Public Sub Add(Child As ClassChild)
Set Child.Parent = Me
this.Childs.Add Child, CStr(Child.Field1)
End Sub
Public Sub Remove(vItem As Variant)
this.Childs.Remove vItem
End Sub
Private Sub Class_Initialize()
Set this.Childs = New Collection
End Sub
Private Sub Class_Terminate()
Debug.Print "ClassParent_Terminate"
End Sub
不幸的是,通过这种构造,每当我想使用 Set Parent = Nothing 删除父对象时,都不会从内存中删除任何子对象。
到目前为止,我总是编写一个额外的显式 Terminate 方法,如下所示
Public Sub Terminate()
Dim Child As ClassChild
Do While this.Childs.Count > 0
Set Child = this.Childs.Item(1)
Set Child.Parent = Nothing
this.Childs.Remove (1)
Set Child = Nothing
Loop
End Sub
现在,当我想删除父对象时,我会这样做
Parent.Terminate
Set Parent = Nothing
现在终于是我的问题了。可以做得更好/更正确吗?如果有任何建议,我将不胜感激。
附注 如果代码有点长,请原谅。我尝试尽可能简单地写出它来显示问题。
最佳答案
VBA 使用引用计数来处理内存中的对象。只要至少有一个对象变量指向它,对象就会保留在内存中。由于您从父级引用子级,从子级引用父级,因此您构建了一个所谓的循环引用,只能通过手动从内存中删除引用/对象来删除该引用/对象,这实际上是在最后一步中展示的。
关于vba - 创建引用父类的类 - 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75988542/