如果对象数组声明为 Variant 类型(以便轻松检查它是否使用 IsEmpty 函数初始化),那么,如果随后定义的数组元素被引用为 With 的对象表达式 语句(例如
With VariantObjArray(i) ...
),那么该对象变量数组元素将被错误地释放(尽管 With 语句的对象变量的隐式副本将正确地用于单个后续执行 - 通过 With 的范围陈述)。
此外,数组元素对象变量的错误释放可能是内存泄漏,因为它是在执行 With 表达式时立即发生的,而不是任何标准释放机制的结果,例如退出 With 语句或从子例程返回或被显式设置为 Nothing。
Sub DemoVariantObjArrayBug()
Dim i As Integer
Dim NextWkSh As Worksheet
Static VariantObjArray As Variant
If IsEmpty(VariantObjArray) Then 'Check to avoid unnecessary re-allocation of static or global array variable
ReDim VariantObjArray(1 To ThisWorkbook.Worksheets.Count)
For Each NextWkSh In ThisWorkbook.Worksheets
i = i + 1: Set VariantObjArray(i) = ThisWorkbook.Worksheets(i)
Next NextWkSh
End If
Stop 'and, to observe the bug, open the Locals window, expand its view of VariantObjArray, single step through
'the following code and observe each VariantObjArray element being deallocated with each cycle's execution
'of the "With" statement:
For i = LBound(VariantObjArray) To UBound(VariantObjArray)
With VariantObjArray(i) 'The bug workaround is to, instead of this, do something like the following...
' Dim SomeWkSh As Object: Set SomeWkSh = VariantObjArray(i)
' With SomeWkSh
Debug.Print """" & .Name & """: CodeName = " & .CodeName & ", Index = " & .Index
End With
Next i
End Sub
解决方法是显式使用中间对象变量,如上面的备用(最初注释)代码所示。 我的问题是:
Cristian Buse 提供了一个更简洁的 bug 解决方法(见上面的评论)。这是我的演示代码和他的解决方法:
Sub DemoVariantObjArrayBug()
Dim i As Integer
Dim NextWkSh As Worksheet
Static VariantObjArray As Variant
If IsEmpty(VariantObjArray) Then 'Check to avoid unnecessary re-allocation of static or global array variable
ReDim VariantObjArray(1 To ThisWorkbook.Worksheets.Count) '*** Naive ReDim that sets the stage for the bug
' ReDim VariantObjArray(1 To ThisWorkbook.Worksheets.Count) As Worksheet '*** Cristian Buse's workaround
For Each NextWkSh In ThisWorkbook.Worksheets
i = i + 1: Set VariantObjArray(i) = ThisWorkbook.Worksheets(i)
Next NextWkSh
End If
Stop 'and, to observe the bug, open the Locals window, expand its view of VariantObjArray, single step through
'the following code and observe each VariantObjArray element being deallocated with each cycle's execution
'of the "With" statement:
For i = LBound(VariantObjArray) To UBound(VariantObjArray)
With VariantObjArray(i) 'The bug workaround is to, instead of naively re-dimensioning the array as
'an (implicit) Variant, above, re-dimension it as a specific type (Worksheet).
Debug.Print """" & .Name & """: CodeName = " & .CodeName & ", Index = " & .Index
End With
Next i
End Sub