这是循环引用的普遍问题。那里有很多关于它的东西,一般的结论是它们是要尽可能避免的。
因此,当您拒绝在每个类中存储对另一个类的引用集合时,您是正确的。在 VBA 中,这将导致内存泄漏,因为基于引用计数的垃圾收集器永远不会销毁具有循环引用的对象,即使不再需要它们一起形成的组。
但如果你确实需要这样的双向关联呢?
有不同的解决方案来处理循环引用,使用不同的技术。在 VBA 中,您需要一种机制来释放交叉引用,在您知道不再需要它们的某个地方。换句话说,您需要以某种方式管理您自己引用的生命周期。
一种可能的实现是维护一个活动组的全局字典。当你想删除一个组时,比如说在代码中某处存在的某个过程中,你首先释放(清空)它的学生集合。这将打破循环引用,让垃圾收集器正常工作。以下是这种可能实现的框架。
'In class clsUser:
Public id as String '<~~ could be any type of identifier, such as Integer
Public groups as New Dictionary
Public Sub subscribeToGroup(g as clsGroup)
Me.groups.add g.id, g
End Sub
Public Sub unsubscribeFromGroup(g as clsGroup)
Me.groups.Remove g.id
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''
'In class clsGroup:
Public id as String '<~~ could be any type of identifier, such as Integer
Public users as New Dictionary
Public Sub registerUser(u as clsUser)
Me.users.add u.id, u
End Sub
Public Sub unregisterUser(u as clsUser)
Me.users.Remove u.id
End Sub
Public Sub removeAllUsers() 'empty the users collection, break the circular reference
For Each u In users: u.unsubscribeFromGroup(Me): Next
users.RemoveAll
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''
您在某个地方(即全局变量,或在某个名为 GroupManager 的类中)有一个组字典,以及创建或删除组的方法。
Public AllGroups as Dictionary
Function addGroup(id as String) as clsGroup
Set addGroup = new clsGroup
addGroup.id = id
AllGroups.Add id, addGroup
End Function
Sub removeGroup(g as clsGroup)
' Explicitly Tell the group to free its users before going away.
' This would not be needed if we didn't have circular references!
g.removeAllUsers
AllGroups.Remove g.id
End Sub
现在,循环引用消失了,组将被销毁(没有内存泄漏),因为没有任何东西持有对它的任何引用。