VBA 双向链接两个对象
VBA Linking two Objects Bidirectionally
我有两个对象,clsGroup 和 clsUser。用户和组是独立的对象。
- 每个用户可以在任意数量的组中。
- 每个组可以包含任意数量的用户。
不是存储属于每个用户的组列表,以及属于每个对象中每个组的用户列表,VBA 是否提供任何方式 link 他们以便从用户对象我们可以获得与该用户关联的组列表,从组对象我们可以获得与该组关联的用户列表?
我试图避免在用户和组中创建集合,因为同步会出现问题。
这是循环引用的普遍问题。那里有很多关于它的东西,一般的结论是它们是应该尽可能避免的东西。
因此,当您拒绝在每个 class 中存储对另一个 class 的引用集合时,您是正确的。在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 等的 class 中)一个组字典,以及创建或删除组的方法.
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
现在,循环引用消失了,组将被销毁(没有内存泄漏),因为没有任何内容持有对它的任何引用。
我有两个对象,clsGroup 和 clsUser。用户和组是独立的对象。
- 每个用户可以在任意数量的组中。
- 每个组可以包含任意数量的用户。
不是存储属于每个用户的组列表,以及属于每个对象中每个组的用户列表,VBA 是否提供任何方式 link 他们以便从用户对象我们可以获得与该用户关联的组列表,从组对象我们可以获得与该组关联的用户列表?
我试图避免在用户和组中创建集合,因为同步会出现问题。
这是循环引用的普遍问题。那里有很多关于它的东西,一般的结论是它们是应该尽可能避免的东西。
因此,当您拒绝在每个 class 中存储对另一个 class 的引用集合时,您是正确的。在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 等的 class 中)一个组字典,以及创建或删除组的方法.
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
现在,循环引用消失了,组将被销毁(没有内存泄漏),因为没有任何内容持有对它的任何引用。