vba Dim As New vs Dim / Set 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42656468/
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-12 12:15:16  来源:igfitidea点击:

What's the difference between Dim As New vs Dim / Set

vba

提问by Combinatix

In VBA, I can create objects one of two ways:

在 VBA 中,我可以通过以下两种方式之一创建对象:

'First way
Dim myCol1 As New Collection

'Second way
Dim myCol2 As Collection
Set myCol2 = New Collection

myCol1.Add "AAA"    'Works
myCol2.Add "BBB"    'Works as well

Is the second way just a more verbose version of the first way, or is there actually a difference between the myCol1 and myCol2 objects?

第二种方式只是第一种方式的更详细版本,还是 myCol1 和 myCol2 对象之间实际上存在差异?

回答by ThunderFrame

There are several key differences. You should definitely prefer the second Dim/Setapproach.

有几个关键区别。您绝对应该更喜欢第二种Dim/Set方法。

Reason 1- With As New, the object doesn't get created until a property or method of that object is called, but look at this example where setting the object to Nothing, and then calling a property/method causes the object re-instantiate itself:

原因 1- 使用As New,在调用该对象的属性或方法之前不会创建对象,但请查看此示例,其中将对象设置为 Nothing,然后调用属性/方法会导致对象重新实例化自身:

Sub ShortcutInstantiation()

  Dim x As New Collection

  x.Add "FOO", "BAR"
  Set x = Nothing

  'This line implicitly recreates a new Collection
  Debug.Print x.Count

  Debug.Print x Is Nothing 'Prints False

End Sub

Sub SafeInstantiation()

  Dim x As Collection
  Set x = New Collection

  x.Add "FOO", "BAR"
  Set x = Nothing

  'Throws error because x is nothing
  Debug.Print x.Count

End Sub

Reason 2The As Newapproach is slower, because VBA needs to check if it has instantiated the object before every singleproperty or method call.

原因 2As New方法较慢,因为 VBA 需要在每个属性或方法调用之前检查它是否已实例化对象。

Look at this pseudo code to see what VBA is doing behind the scenes:

看看这个伪代码,看看 VBA 在幕后做了什么:

Sub NotSoShortcutInstantiation()

  Dim x As New Collection

  If x Is Nothing Then Set x = New Collection
  x.Add "FOO", "BAR"

  If x Is Nothing Then Set x = New Collection
  x.Add "FIZZ", "BUZZ"

  If x Is Nothing Then Set x = New Collection
  x.Add "CAR", "DOOR"

  If x Is Nothing Then Set x = New Collection
  Debug.Print x.Count

End Sub

Reason 3There can be critical timing differences if you object constructor does something afteryou expect it to, rather than when you explicitly instantiate it:

原因 3如果对象构造函数预期之后执行某些操作,而不是在显式实例化它时执行某些操作则可能存在严重的时序差异:

Compare the results of this code:

比较这段代码的结果:

Sub InstantiationTiming()

  Dim foo As String

  Dim x As New Class1
  Debug.Print Format(Now(), "hh:mm:ss") & " x should be ready"
  foo = x.foo

  Dim y As Class1
  Set y = New Class1
  Debug.Print Format(Now(), "hh:mm:ss") & " y should be ready"
  foo = y.foo

End Sub

The As Newapproach prints:

As New方法打印:

06:36:57 x should be ready
06:36:57 Class Initialized

The Set y = Newapproach prints:

Set y = New方法打印:

06:36:57 Class Initialized
06:36:57 y should be ready

回答by S Meaden

The As Newconstruct has legitimate uses. In a class, with a module level variable when you do not know which method will be called first then it saves some lines of code. So some code snippet I have lying around in a class is given here

As New构造具有合法用途。在一个类中,当您不知道首先调用哪个方法时,使用模块级变量可以节省一些代码行。所以这里给出了我在课堂上闲逛的一些代码片段

Option Explicit

Private mdicQueryStringParams As New Scripting.Dictionary

Function SafeItem(ByVal sKey As String, ByRef pvItem As Variant) As Boolean

    If mdicQueryStringParams.Exists(sKey) Then
        pvItem = mdicQueryStringParams.Item(sKey)
        SafeItem = True
    End If

End Function

Imagine very many more methods that rely upon an initialised mdicQueryStringParams. You'd have to write guard code to ensure that it was created in all of these methods.

想象一下更多依赖于初始化的方法mdicQueryStringParams。您必须编写保护代码以确保它是在所有这些方法中创建的。

Now at this point you're saying but you can use Sub Class_Initializeto Newup upon class creation. Like this

现在,您说的是,但您可以使用Sub Class_InitializeNew创建类。像这样

Private Sub Class_Initialize()
    Set mdicQueryStringParams = New Scripting.Dictionary
End Sub

But suppose I want to recycle/reset part of the class's state then I could write a Clear method which sets mdicQueryStringParamsto Nothing. In this case Sub Class_Initialisewon't run again. Here on SO Mat's Mughas taught me that Static classes are possible in VBA (thanks!) so sometimes Sub Class_Initialisewill only run once.

但是假设我想回收/重置类的部分状态,那么我可以编写一个设置mdicQueryStringParamsNothing. 在这种情况下Sub Class_Initialise不会再次运行。SO Mat 的 Mug告诉我,在 VBA 中可以使用静态类(谢谢!)所以有时Sub Class_Initialise只会运行一次。

(^ Admittedly I could set it to a New instance in the Clear method, yes, yes, I know, I know)

(^ 诚然,我可以在 Clear 方法中将其设置为 New 实例,是的,是的,我知道,我知道)

The point is with the As Newsyntax you get a resurrectingvariable as well as auto-initialisation. Surely as developers this is another technique/pattern in our toolbox that we should exploit and not ban.

关键是使用As New语法你会得到一个复活变量以及自动初始化。当然,作为开发人员,这是我们工具箱中的另一种技术/模式,我们应该利用而不是禁止。

In truth, I use it infrequently but I just don't like banningstuff.

事实上,我很少使用它,但我只是不喜欢禁止某些东西。