Class_Terminate不从表单中触发对象

Eri*_*k A 4 ms-access vba access-vba

我有一个非常简单的表单,它使用一个非常简单的类来处理一些事情.那个班级有一个Class_Terminate自己清理的子.但是,当表单关闭时,似乎没有触发.

MCVE:

表单Form1,一个名为Text0的文本框,没有进一步的控件

Private myClass1 As Class1

Private Sub Form_Load()
    Set myClass1 = New Class1
    myClass1.InitForm Me
End Sub
Run Code Online (Sandbox Code Playgroud)

Class Class1

Public theForm As Form
Private WithEvents SomeTextbox As TextBox
Public Sub InitForm(frm As Form)
    Set theForm = frm
    Set SomeTextbox = frm.Text0
End Sub
Private Sub Class_Terminate()
    MsgBox "Class1 terminated succesfully"
End Sub
Run Code Online (Sandbox Code Playgroud)

但是,当我关闭表单时,类终止处理程序不会触发.

我尝试在类中取消设置Form对象:

Private Sub Form_Unload(Cancel As Integer)
    Set myClass1.theForm = Nothing
End Sub
Run Code Online (Sandbox Code Playgroud)

但随之而来的是混乱:关闭表单后类终止处理程序触发,但之后立即访问硬崩溃而没有任何错误消息!

Eri*_*k A 5

关闭表单时,Access无法正常清理表单对象.

这意味着:如果对象具有对表单的开放引用,则表单对象仍然存在.如果没有对它的引用,它只能被垃圾收集器删除.

表单的第一个版本是创建内存泄漏:表单对象Form_Form1具有对Class1(通过MyClass1变量)的引用,通过变量Class1引用表单对象theForm.这导致了参考循环.终止处理程序没有触发,因为类永远不会终止,它无限期地保留在内存中,关闭并重新打开表单只是打开了一个新的类实例.

第二个版本导致了一个问题:在基准循环被打破,引用Form1发布第一(因为还有是参考Class1Form1),造成垃圾收集器来清理,然后引用Class1被释放,垃圾收集器试图清理Class1,包括文本框对象SomeTextbox,导致访问硬崩溃,因为表单对象已被清理,文本框对象无效.

解决方案是通过删除对Class1first的所有引用来中断引用循环.这不会导致崩溃.

Private Sub Form_Unload(Cancel As Integer)
    Set myClass1 = Nothing
End Sub
Run Code Online (Sandbox Code Playgroud)

这会导致垃圾收集器首先清理Class1实例,释放对Text0的引用,然后清除表单对象,因为没有人打开引用它.

  • 好奇如果[this](https://rubberduckvba.wordpress.com/2018/09/11/lazy-object-weak-reference/)也可以成为一个解决方案 (3认同)