【问题标题】:How to destroy an object如何销毁一个对象
【发布时间】:2017-06-29 02:47:55
【问题描述】:

似乎Set Object = Nothing 没有破坏这段代码中的Fs 对象:

Sub Test2()
    Dim Fs As New FileSystemObject
    Set Fs = Nothing
    MsgBox Fs.Drives.Count ' this line works
End Sub

最后一行没有错误!这意味着Fs 对象仍然存在,对吧?

那么如何销毁这个Fs 对象。

【问题讨论】:

  • 让它超出范围?为什么你觉得有必要摧毁它?
  • @Comintern,我使用这个对象来读取保存在 TrueCrypt 卷中的文本文件,使用它后我无法卸载这个卷,也许如果我销毁它我可以卸载这个卷。
  • @Comintern 在某种意义上是重复的,但不知道问题答案的人甚至不会怀疑它是重复的,也不知道如何搜索它。
  • 这种不直观的行为正是 Rubberduck 的 Object variable is self-assigned 代码检查背后的原因。在本地范围内使用As New 会改变引用为空的工作方式,因为Dim 语句不是可执行语句,因此变量在整个过程中都在范围内;在清空后引用它只是重新创建对象。

标签: excel ms-access vb6 vba


【解决方案1】:

确保正确销毁对象的另一种方法是将其对象引用产生到 With 块(即不声明局部变量):

Sub Test()
    With New FileSystemObject
        MsgBox .Drives.Count
    End With
End Sub

该对象只存在于With 块中,当执行到达End With 标记时,如果您使用自定义类模块尝试它,您会注意到该类的Class_Terminate 处理程序有效地运行确认对象的正确销毁。

至于As New 怪癖as was already explained,如果您打算在该范围内将对象引用设置为Nothing,请不要使用As New 声明它,因为VBA 将对象引用设置为Nothing,但一旦您再次重新引用它,它也会愉快地(“有帮助”)为您创建一个新实例,只是为了验证对象Is Nothing

旁注,这种(烦人的)违反直觉的行为是Rubberduck对象变量是自分配的代码检查背后的原因:

(注意:如果您有要检查的代码,请知道它在实际 VBE 中的运行速度比在网站上快

(如果还不清楚的话:我积极参与 Rubberduck 项目)

【讨论】:

  • 非常感谢@Mat's Mug。 user3598756 和 Zerk 的答案很好,对我有帮助,但我认为你的答案是最好的,也应该是帮助其他用户的公认答案。
  • 嗯,我不是要在这里偷一个复选标记,只是为了提供附加信息-无论如何谢谢!
  • 我知道Dim 然后Set 并在我发布我的问题之前对其进行测试,但我正在寻找其他信息,例如您的答案,再次感谢您。
【解决方案2】:

它必须与“声明和实例化”模式有关,通常被称为“要避免的”模式

如果将它们拆分,则将其设置为:Nothing

Sub Test2()
    Dim Fs As FileSystemObject
    Set Fs = New FileSystemObject
    Set Fs = Nothing
    MsgBox Fs.Drives.Count ' this line DOESN'T work
End Sub

【讨论】:

  • 非常感谢 user3598756,我很抱歉,但我认为 @Mat's Mug 发布了一个很好的答案。
【解决方案3】:

这个修改后的代码似乎工作正常。似乎与同一行上的 dim/new 有细微差别。希望其他人可以对推理提供更好的想法。

正如其他人评论的那样,如果它是子内的暗淡,那么它将在子完成后被收集。

Sub Test2()
    Dim Fs As FileSystemObject
    Set Fs = New FileSystemObject
    Set Fs = Nothing
End Sub

【讨论】:

  • 我遇到了同样的问题,即在代码完成运行后没有清除的集合。我在我的模块顶部这样声明:Dim coll As New Collection。我删除了 New 关键字,然后在我的 sub 中添加了这个:Set Coll = New Collection。我尝试了不同的方法,例如 = nothing 但这是唯一有效的方法。