VBA:在两种方式中声明一个新对象的区别? (试图了解我的解决scheme为什么工作)
我在一个循环内创build一个新的对象,并将该对象添加到一个集合中; 但是当我读回集合后,它总是完全填充了我添加的最后一个对象。 我提出了两种解决方法,但我不明白为什么我的初始实现是错误的。
原版的:
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; 我显然不是创build新的对象,而是每次通过循环使用同一个对象,尽pipe声明在循环内部。
所以,我Next
一行之前添加了Set oMatch = Nothing
,并且解决了这个问题,现在是0到10.所以如果旧的对象被明确的销毁,那么它愿意创build一个新的? 我会认为通过循环的下一个迭代会导致在循环内声明的东西被破坏,由于范围?
好奇的是,我尝试了另一种声明新对象的方式: Dim oMatch As clsMatch: Set oMatch = New clsMatch
。 这也是0到10。
任何人都可以向我解释为什么第一次执行是错误的?
Fink的答案正确地解决了你的主要问题,那就是你的第一个循环将多个引用添加到你的集合的同一个“clsMatch”实例中。 我将详细说明为什么你的修复工作。
在VBA中,一行如下:
Dim c As New Collection
实际上并没有创build一个新的集合。 “暗淡”的声明总是只是一个声明。 把“新的”forms看成是这样的简写:
Dim c As Collection '... '(later, when you're about to use 'c') If c Is Nothing Then Set c = New Collection End If '...
这就是为什么通过将包含它的variables设置为“Nothing”来破坏你的引用正在工作。 [注:任何人编辑这个说“不是” – 这改变了答案的含义,并使其不正确。 请阅读原来的问题。 OP发现把这个variables设置为Nothing 没有问题,我解释了为什么会出现这种情况。]当循环返回到“oMatch.setLineNumber”行时,VBA“帮助”创build了一个“clsMatch”为你的'oMatch'variables引用,然后你在你的集合中有多个不同的实例。
明确地做这可能会更好:
Dim oMatch As clsMatch For i = 0 To 10 Set oMatch = New clsMatch oMatch.setLineNumber i oCollection.Add oMatch Next
请注意(与C / C ++或?? .NET不同),“Dim”声明的位置并不重要。 它并没有在循环中被“执行”多次,而且它所声明的范围是程序范围的,即使它出现在循环内部。
当您将oMatch对象添加到集合时,它将传递variablesBy Memory Reference。 当你再次声明oMatch为一个新的clsMatch时,它不会销毁你创build的第一个对象本地内存指针。 它只是简单地给你与你创build的第一个oMatch对象相同的本地内存位置,即使你已经声明它是一个新的对象。 VBA使用ByRef作为默认的内存传递技术。 然后更新收集存储器位置,两者都指向相同的存储器位置,具有新更新的行号。 因此,所有的集合内存指针都将指向您创build的最后一个对象。
当你设置oMatch = Nothing时,它会重置本地内存指针,并且会用一个新的本地内存指针创build一个新的oMatch对象,集合的指针将全部指向它们正确的对象。
VBA默认的内存传递是ByRef,如VB所示,默认是ByVal,所以你可能会偶尔碰到这个警告。
在课堂模块中有“作为新的”的有效用法。 考虑这个:
模块一:
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
class myClassX:
Public subClass as new referencedClass ' automatic instanciation of subclass:
class referencedClass:
Public someThing as string