VBA:声明新对象的两种方式的区别?(试图了解为什么我的解决方案有效)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2478097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 10:20:21  来源:igfitidea点击:

VBA: Difference in two ways of declaring a new object? (Trying to understand why my solution works)

vbasyntaxaccess-vba

提问by Matt

I was creating a new object within a loop, and adding that object to a collection; but when I read back the collection after, it was always filled entirely with the last object I had added. I've come up with two ways around this, but I simply do not understand why my initial implementation was wrong.

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

Original:

原来的:

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

This resulted in every lineNumber being 10; I was obviously not creating new objects, but instead using the same one each time through the loop, despite the declaration being inside of the loop.

这导致每个 lineNumber 为 10;我显然不是在创建新对象,而是在循环中每次都使用相同的对象,尽管声明在循环内部。

So, I added Set oMatch = Nothingimmediately before the Nextline, and this fixed the problem, it was now 0 to 10. So if the old object was explicitly destroyed, then it was willing to create a new one? I would have thought the next iteration through the loop would cause anything declared within the loop do be destroyed due to scope?

所以,我Set oMatch = Nothing在该Next行之前添加了,这解决了问题,现在是 0 到 10。所以如果旧对象被显式销毁,那么它愿意创建一个新对象吗?我会认为循环的下一次迭代会导致循环中声明的任何内容由于范围而被破坏?

Curious, I tried another way of declaring a new object: Dim oMatch As clsMatch: Set oMatch = New clsMatch. This, too, results in 0 to 10.

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

Can anyone explain to me why the first implementation was wrong?

谁能向我解释为什么第一个实现是错误的?

回答by jtolle

Fink's answer gets your main problem right, which is that your first loop is adding multiple references to the same instance of 'clsMatch' to your collection. I'll just elaborate on why your fix works.

Fink 的回答正确解决了您的主要问题,即您的第一个循环是向您的集合中添加对同一 'clsMatch' 实例的多个引用。我将详细说明为什么您的修复有效。

In VBA, a line like:

在 VBA 中,像这样的一行:

Dim c As New Collection

doesn't actually create a new collection. The 'Dim' statement is always just a declaration. Think of the 'As New' form as being shorthand for this:

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

'...

That is why destroying your reference by setting the variable that contained it to 'Nothing' was working. [NOTE: to whomever edited this to say "was not" - that changes the meaning of the answer and makes it incorrect. Please read the original question. The OP found that setting the variable to Nothing didwork, and I was explaing whythat was the case.] When the loop came back around to the 'oMatch.setLineNumber' line, VBA "helpfully" created a new instance of 'clsMatch' for your 'oMatch' variable to refer to, and then you got multiple different instances in your collection.

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

It would probably be better to do this explicitly:

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

Dim oMatch As clsMatch   

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

Note that (unlike in C/C++ or ??.NET) it doesn't matter where the 'Dim' declaration goes. It's not being "executed" multiple times inside the loop, and the scope of what it declares is procedure-wide even though it appears inside the loop.

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

回答by Fink

When your adding the oMatch object to the collection, its passing the variable By Memory Reference. When you are declaring oMatch again as a new clsMatch, its not destroying the first objects local memory pointer you had created. Its simply giving you the same local memory location as the first oMatch object you had created even though you have declared it as a new object. VBA uses ByRef as the default memory passing technique. The collection memory locations are then updated, both pointing to the same memory location, with the newly updated line number. Thus all collection memory pointers are going to point to the same last object you had created.

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

When you set oMatch = nothing, it resets the local memory pointer, and will create a new oMatch object with a new local memory pointer, and the collection's pointers will all point to their correct objects.

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

VBA's default memory passing is ByRef, as apposed to VB where the default is ByVal, so you might run into this caveat every now and again.

VBA 的默认内存传递是 ByRef,与 VB 相同,其中默认值是 ByVal,因此您可能时不时地遇到这个警告。

回答by user3402722

There is a valid use for "as new" within class modules. Consider this:

在类模块中“作为新的”是有效的。考虑一下:

module 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

class myClassX:

类 myClassX:

Public subClass as new referencedClass ' automatic instanciation of subclass:

class referencedClass:

类引用类:

Public someThing as string