【问题标题】:What is the reason for not instantiating an object at the time of declaration?声明时不实例化对象的原因是什么?
【发布时间】:2011-11-13 20:58:53
【问题描述】:

我最近不得不深入研究一些 VB6 代码,并且到处都看到了这种模式:

dim o as obj
set o = new obj

为什么不这样?

dim o as new obj

我记得 15 年前有一个很好的理由,但我不记得现在是什么了。有人记得吗?理由还成立吗?

【问题讨论】:

  • 嗯,有趣,我在 VB6 中编码了 3 年,我记得这两者是完全正确的。
  • dim o as new obj 在第一次访问时被实例化,而不是之前。因此,对其进行的每个属性/方法调用都会产生检查Nothing 变量的开销。
  • @wqw 每个属性都有检查 Nothing 的开销,即使在对象被实例化后或只是第一次实例化之后?
  • @AngryHacker 是的,因为除非对象是“Not Nothing”,否则您根本无法访问对象的属性。所以每个访问前面都有一个隐含的“If obj Is Nothing Then Set obj = New MyObj”。
  • @wqw 不要忘记,一旦在循环中使用,“New obj”方法将不会破坏和重新创建 obj,但是如果您执行“Dim o As obj”和“Set o = New obj”,那么每次运行这个序列时,它都会销毁并重新创建“o”变量。特别是如果 obj 是 Collection 类型,并且它没有被销毁和重新创建(就像只执行“Dim o As New Collection”时那样),每次您将项目添加到 Collection 时(在这种情况下为“o”,当一个循环)它只会继续将项目重新添加到集合中,并且您将获得前一个循环中的陈旧数据,差别很大。看我的回答。

标签: vb6


【解决方案1】:

可能还有其他原因,但在 VB6 中,当您对对象进行调暗时使用 New 关键字可能会导致意外结果,因为 VB 将在对象被引用时实例化该对象。

Dim objMyObject as New SomeObject

Set objMyObject = Nothing   ' the object is nothing

If objMyObject Is Nothing Then  ' referencing the object instantiates again
   MsgBox "My object is destroyed"  ' what you would probably expect
Else
   MsgBox "My object still exists"
End If

【讨论】:

  • 这正是原因。
  • 这个答案正朝着正确的方向发展,但可能不是最好的措辞?我不会使用unpredictable。结果是完全可预测的,但对于大多数开发人员来说往往出乎意料。结果还可能意味着编程错误会在运行时导致细微的错误行为,而不是一个简单的异常“未设置对象变量”
  • @MarkJ 你的观点很好,我相应地编辑了答案
【解决方案2】:

这个问题涉及到经验丰富的程序员真正不喜欢 VB6 的众多原因之一。 New 关键字改变了声明变量的工作方式。例如:

Dim MyObject As MyClass
Set MyObject = New MyClass
Set MyObject = Nothing
Call MyObject.MyMethod()

...抛出运行时异常,而这个:

Dim MyObject As New MyClass
Set MyObject = Nothing
Call MyObject.MyMethod()

... 没有。就个人而言,如果我努力将变量设置为Nothing,那么再次引用它几乎肯定是一个错误,我真的希望程序崩溃,非常感谢。在类在初始化程序(构造函数)中分配资源并需要在析构函数中删除资源的情况下,这一点尤为重要。编写错误地引用设置为Nothing 的变量的代码相当容易,也许当您想要检查结果值或其他内容时。这样做可能会导致类被再次实例化,从而占用所有不必要的资源。

这种奇怪行为的原因是 VB6 的表单(它们是类)按照新手所期望的方式工作。有一个隐式声明的 global 变量,其名称和类型与每个定义的形式相同,所以:

Call frmMain.Show

... 不会崩溃。这是相同的行为。真的在做:

If frmMain Is Nothing Then
    Set frmMain = New frmMain
End If
Call frmMain.Show

这与我们在其他面向对象语言中所习惯的做法大相径庭,因此,在我看来,这是一个坏主意。它试图隐藏MyObject 是一个引用类型的事实,然而,当你写这样的东西时(不使用Set):

MyObject = New MyClass

...然后你得到一个 runtime 异常而不是编译器错误,因为你没有使用Set 命令。编译器知道它是一个引用类型...为什么我必须使用Set,即使我这样做了,为什么不早点告诉我呢?

无论如何,要回答您的问题,您很少需要使用 Dim ... New 语法所暗示的行为,因为您想控制对象的构造和销毁。事实上,唯一有意义的是在构建全局单例对象(例如上面的frmMain)时,您只需要语法糖。我认为无论如何全局单例都是一个坏主意,所以如果我可以关闭使用Dim ... New 语法的能力,我会的。

【讨论】:

  • 在众多不喜欢vb6的重要原因中,我想说这个几乎不值得一提,哈哈
  • @Mat'sMug 关于 IDE 足够公平,但类似的属性对于 VB6 程序员来说基本上是不可见的。实际上,它们甚至在任何地方都有记录吗?
【解决方案3】:

这里还有一个警告:

For x = 1 to 100
   dim obj as new MyObject

   'Do something with obj
Next

您可能期望一个新对象被实例化 100 次,但您会发现它只在第一次被实例化。这个早就让我措手不及了。

尽管如此,我仍然一直使用这种表示法。只需确保您了解这种行为即可。

【讨论】:

  • 这也让我措手不及
【解决方案4】:

我想补充一下 Brandon Moore 的答案...

所以从循环继续...

For x = 1 to 100
  Dim obj as New Collection
  obj.Add "New String Number " & x
Next x

即使您在 x = 1 时向 obj 添加了 20 个项目,但当 x = 2 时,所有这 20 个项目仍然存在!然而,如果你确实设置了 obj= new myObject 那么它不会!这是最重要的原因,因为我曾经在我的代码中的一个大循环区域中陷入这种情况,在整个程序中添加了一些东西,我不知道为什么,没有任何东西被删除或重置。

所以,如果不是:

  Dim obj as New Collection

下面是你写的:

  Dim obj as Collection
  Set obj = New Collection

然后您将每次重置 obj Collection,这可能是您想要的,但如果您只想设置一次,请使用 As New Collection 方法。但是,如果你只想设置一次,你可能会把它放在循环之外。

另外,如果你不是在循环中运行,但是变量(Collection)是在静态函数中定义的,或者是用 static 关键字定义的,同样的事情也适用,不运行 Set obj = New Collection 会确保您上次使用 obj/Collection 的数据过时,这可能非常糟糕。

因此,总而言之,这两种方法实际上是非常不同的(并且可以有不同的行为)!

【讨论】:

    猜你喜欢
    • 2019-12-10
    • 1970-01-01
    • 2019-08-01
    • 2017-05-05
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多