VBA:两种声明新对象的方式有何不同?(试图理解为什么我的解决方案有效)

Mat*_*att 30 syntax vba access-vba

我在循环中创建了一个新对象,并将该对象添加到集合中; 但是当我读回之后,它总是被我添加的最后一个对象填满.我想出了两种解决方法,但我根本不明白为什么我的初始实现是错误的.

原版的:

Dim oItem As Variant
Dim sOutput As String
Dim i As Integer

Dim oCollection As New Collection
For i = 0 To 10
    Dim oMatch As New clsMatch
    oMatch.setLineNumber i
    oCollection.Add oMatch
Next
For Each oItem In oCollection
    sOutput = sOutput & "[" & oItem.lineNumber & "]"
Next
MsgBox sOutput
Run Code Online (Sandbox Code Playgroud)

这导致每行数为10; 我显然没有创建新对象,而是每次通过循环使用相同的对象,尽管声明在循环内部.

所以,我在行Set oMatch = Nothing之前立即添加Next,这解决了问题,它现在是0到10.所以如果旧对象被明确销毁,那么它是否愿意创建一个新对象?我原以为通过循环的下一次迭代会导致循环中声明的任何东西因范围而被破坏?

好奇,我尝试了另一种声明新对象的方法:Dim oMatch As clsMatch: Set oMatch = New clsMatch.这也导致0到10.

任何人都可以向我解释为什么第一次实施是错误的?

jto*_*lle 33

Fink的答案让你的主要问题正确,那就是你的第一个循环就是在你的集合中添加对同一个'clsMatch'实例的多个引用.我将详细说明你的修复工作原理.

在VBA中,一行如下:

Dim c As New Collection
Run Code Online (Sandbox Code Playgroud)

实际上并没有创建新的集合.'Dim'语句总是一个声明.将'As New'形式视为速记:

Dim c As Collection
'...

'(later, when you're about to use 'c')

If c Is Nothing Then
    Set c = New Collection
End If

'...
Run Code Online (Sandbox Code Playgroud)

这就是为什么通过将包含它的变量设置为'Nothing'来破坏你的引用的原因.[注意:对于任何编辑过的人说"不是" - 这会改变答案的含义并使其不正确.请阅读原始问题.OP发现将变量设置为Nothing 确实有效,我正在解释为什么会出现这种情况.]当循环回到'oMatch.setLineNumber'行时,VBA"帮助"创建了一个新的'clsMatch'实例要引用您的'oMatch'变量,然后您的集合中有多个不同的实例.

明确地这样做可能会更好:

Dim oMatch As clsMatch   

For i = 0 To 10                
    Set oMatch = New clsMatch                
    oMatch.setLineNumber i                
    oCollection.Add oMatch                
Next  
Run Code Online (Sandbox Code Playgroud)

请注意(与C/C++或?? .NET不同),"Dim"声明的位置并不重要.它并没有在循环中多次"执行",并且它声明的范围是程序范围的,即使它出现在循环内部.

  • 这就是为什么你经常会看到(正确的,IMO)律师,如Jonathan Allen对你的问题的评论,即"As New"通常是最好的避免.'Dim <variable> As <class>'声明东西.'Set <variable> = New <class>'创建东西.但是'Dim <variable> As New <class>'是一个奇怪的混合体.结合"Dim As New"形式看起来它正在创建一个实例,然后事实是VBA会让你把它放在一个循环中并且混乱是可以理解的. (4认同)

Fin*_*ink 9

将oMatch对象添加到集合时,它会传递变量By Memory Reference.当您再次将oMatch声明为新的clsMatch时,它不会破坏您创建的第一个对象本地内存指针.它只是为您提供了与您创建的第一个oMatch对象相同的本地内存位置,即使您已将其声明为新对象.VBA使用ByRef作为默认的内存传递技术.然后使用新更新的行号更新收集存储器位置,两者都指向相同的存储器位置.因此,所有集合内存指针都将指向您创建的最后一个对象.

当你设置oMatch = nothing时,它会重置本地内存指针,并使用新的本地内存指针创建一个新的oMatch对象,并且集合的指针都指向它们正确的对象.

VBA的默认内存传递是ByRef,与VB相似,默认为ByVal,所以你可能会不时地遇到这个警告.