vba - 创建引用父类的类 - 最佳实践

标签 vba

我长期以来一直在努力解决如何正确创建一个引用父类的类,以便在删除父对象时,所有子对象也被删除的问题。我将尝试在下面的示例中演示这一点。

假设我有一个像这样的简单子(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/

相关文章:

excel - 如何以编程方式重新应用数据过滤器?

mysql - 查询数据库后,如何在 Excel 中打印值列表?

ms-access - 如何使用 AutoExec 宏在 Access 启动时为标签分配某些文本?

c# - 如何实现作为约束的抽象类的接口(interface)?

excel - 为什么条件在 Do-Loop 之外起作用,但在其中给出类型不匹配

excel - 区分 "1"和 "11"

excel - 如何在Excel中的多个工作表中删除重复值和原始值

excel - 如何在 Excel VBA 中检查字符串是否为有效的 HHMMSS 值?

Excel VBA - 按照表中的描述添加行

vba - 用于复制单元格并将其粘贴到接下来的 2 个单元格的宏代码