Dim As New与Dim/Set之间有什么区别

Com*_*tix 9 vba

在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
Run Code Online (Sandbox Code Playgroud)

第二种方式是第一种方式的更详细的版本,还是myCol1和myCol2对象之间实际上有区别?

Thu*_*ame 18

有几个关键的区别.你绝对应该选择第二种Dim/Set方法.

原因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
Run Code Online (Sandbox Code Playgroud)

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

看看这个伪代码,看看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
Run Code Online (Sandbox Code Playgroud)

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

比较此代码的结果:

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
Run Code Online (Sandbox Code Playgroud)

As New方法打印:

06:36:57 x should be ready
06:36:57 Class Initialized
Run Code Online (Sandbox Code Playgroud)

Set y = New方法打印:

06:36:57 Class Initialized
06:36:57 y should be ready
Run Code Online (Sandbox Code Playgroud)

  • 也经常在循环中看到与 `as new` 混淆,这让人们认为他们正在获取一个新对象,而实际上他们每次都使用完全相同的引用(及其状态)。 (2认同)
  • 答案是*“在调用该对象的属性或方法之前不会创建对象”*,但它是代码中对该对象的任何引用,而不仅仅是调用其成员。例如,即使是 `Debug.Print x is Nothing` 行也会触发对象的创建,因此它总是打印 `False`。 (2认同)

S M*_*den 6

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
Run Code Online (Sandbox Code Playgroud)

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

现在,在这一点上你说,但你可以使用Sub Class_InitializeNew了在类的创建.像这样

Private Sub Class_Initialize()
    Set mdicQueryStringParams = New Scripting.Dictionary
End Sub
Run Code Online (Sandbox Code Playgroud)

但是假设我想循环/重置类的状态的一部分然后我可以写一个设置mdicQueryStringParams为的Clear方法Nothing.在这种情况下Sub Class_Initialise不会再次运行.在这里,SO Mat的Mug告诉我静态类在VBA中是可能的(谢谢!)所以有时Sub Class_Initialise只会运行一次.

(不可否认,我可以在Clear方法中将其设置为New实例,是的,是的,我知道,我知道)

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

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