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

时间:2010-03-19 14:40:25

标签: vba syntax 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

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

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

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

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

3 个答案:

答案 0 :(得分:33)

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

在VBA中,有一行:

Dim c As New Collection

实际上并没有创建新的集合。 '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

'...

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

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

Dim oMatch As clsMatch   

For i = 0 To 10                
    Set oMatch = New clsMatch                
    oMatch.setLineNumber i                
    oCollection.Add oMatch                
Next  

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

答案 1 :(得分:9)

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

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

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

答案 2 :(得分:3)

类模块中有“as new”的有效用法。考虑一下:

模块a:

Dim mUbelow as myClassX       ' do not use "as new" here 
set mUbelow = new myClassX    ' mUbelow instanciation also instanciates subClass 
                              ' as a referencedClass object
                              ' so you can not forget to do this
mUbelow.subClass.someThing = "good news"  ' without the "as new" below: ==> error

类myClassX:

Public subClass as new referencedClass ' automatic instanciation of subclass:

class referencedClass:

Public someThing as string