【问题标题】:How to Pass a Late Bound Parameter如何传递后期绑定参数
【发布时间】:2009-07-22 21:14:07
【问题描述】:

在 VB6 中,我试图将后期绑定的对象传递给另一个表单。

frmMain.vb

Dim x
Set x = CreateObject("MyOwn.Object")
Dim f as frmDialog
Set f = New frmDialog
f.SetMyOwnObject x

frmDialog

Dim y
Public Sub SetMyOwnObject(ByVal paramX As Variant)
  Set y = paramX
End Sub

y 的内容是一个字符串,其中包含后期绑定对象的类型名称“MyOwn.Object”。 ByVal 和 ByRef 没有区别。有什么线索吗?记不住。

【问题讨论】:

  • 我没有看到此代码有任何问题。你期望它是什么?
  • 你是如何确定y的内容确实是一个字符串?也许它实际上是对象,当你将它传递给一些需要字符串的函数或语句时,它被转换为字符串?
  • 我猜,您只是将鼠标悬停在“Y”上并看到实例的名称。尝试将 Y 的值放在监视窗口中,以查看它确实是您实例化的对象。您还应该能够在监视窗口中看到 Y 的属性。 Byval/ByRef 本身不会改变任何东西(在你的情况下)。
  • 我使用了 VarType(y)。对于 vbString,结果为 8。对象应该是 9。
  • 使用立即窗口中的 Print y 来查找 y 的内容。

标签: vb6 parameters late-binding


【解决方案1】:

我手边没有 VB6 的副本,但我记得或多或少经常做同样的事情,而且我相信我们在方法签名中使用了 Object 而不是 Variant。 Variant 通常很难预测它可能对变量运行的转换类型,而对于 Object,我相当确定 VB 不会尝试任何类型的转换。

【讨论】:

  • 你能举个例子,变体将执行任何类型的转换吗?
  • 如果您在其中存储对象实例,则使用 Variant 不会导致转换。但是,如果对象具有返回值的默认属性或方法,则如果您在需要表达式的上下文中使用该变量,则该变量将评估为默认属性或方法的值。例如,如果您“设置 y = someObject”并且 y 是一个 Variant,并且 someObject 有一个名为 Value 的默认属性,该属性返回一个字符串,那么执行“Debug.Print y”之类的操作将调用 Value,因为 VB6 无法评估对象本身是一个表达式,而 Value 是默认属性。
  • 同理,如果您有一个具有默认属性/方法的对象,并且您使用 Set 将其分配给没有的 Variant,它将分配返回值Variant 的默认属性/方法,而不是对象本身(即它不会产生错误)。其他需要注意的事情,如果您知道对象变量将只存储对象而不是其他类型的数据,那么明确将对象变量“作为对象”调暗的另一个很好的理由。
  • 变体在某些特殊情况下有其用途,但恕我直言,除非您要使用它们的特殊功能,否则最好避免使用它们。 Mike 很好地解释了它们的一些缺点。
【解决方案2】:

我使用了 VarType(y)。结果是8, 对于 vbString。它应该是 9 目的。 – ssorrrell 1 小时前

使用立即窗口中的打印 y 找到 y 的内容。 – 索雷尔 55 分钟前

这似乎证实了我的猜想。 MyOwn.Object 类必须具有返回字符串的默认属性或方法。

因此,当您尝试Debug.Print 它时,它将返回默认属性/方法的值。当您将鼠标悬停在 IDE 中的变量上时,VB6 将显示默认属性/方法的值。当您对y 进行VarType 调用时,它将返回默认属性或方法的变量类型。

原因是当你有一个类型为Variant 的变量存储Object,并且该对象的类定义了默认方法或属性时,该变量将评估为默认方法的返回值或大多数情况下的属性。

您可以通过打开MyOwn.Object 类的对象浏览器 并查看其属性和方法列表来快速检查MyOwn.Object 类是否具有默认成员。如果您看到某个方法或属性的角落有一个带有蓝色小圆圈的图标,则表明该方法或属性是该类的默认成员。如果你找到了,我敢打赌它声明返回一个字符串。

请注意,即使您将所有VariantS 更改为ObjectS,您仍然会在很多地方遇到这种行为。例如,即使 y 被声明为 As Object,执行 Debug.Print y 仍会打印出默认属性或方法的值,执行 VarType(y) 仍将返回 8(字符串)。

确切地知道 VB6 何时使用默认成员以及何时不使用默认成员可能会造成混淆。例如,如果您将y 声明为Object,那么执行TypeName(y) 将返回MyOwn.Class,但VarType(y) 仍将返回8(字符串)。但是,如果您将y 声明为Variant,则TypeName(y) 返回String

如果您使用后期绑定,则很难避免这种副作用,因为您只能将对象变量声明为 ObjectVariant

【讨论】:

  • MyOwn.Object 是一个 .Net 1.1 库,它的属性和成员没有列出,只有类名。我没有看到任何定义的默认属性。
  • 啊哈。由于它是一个 .NET 库,因此该库很可能将类的 ToString 方法公开为默认值。既然你提到你得到的字符串是类的名称,我想说这很可能是正在发生的事情。
  • 我这么说是因为ToString 会返回类的全名,除非它被覆盖。
  • 揭示 ToString 方法可以解释它。
【解决方案3】:

您确定没有省略 Set 关键字,例如

Dim y
Public Sub SetMyOwnObject(ByVal paramX As Variant)
  ' Set y = paramX  ' thought you had this...
  y = paramX        ' ...actually have this
End Sub

如果是这种情况,那么 y 的值将是对象的默认值。您的 MyOwn.Object 类是否有一个属性,该属性返回其类型的描述并已被定义为该类的默认成员(在 VB 对象浏览器中用蓝点标记)?

【讨论】:

  • 出于兴趣,该类是否有默认成员?如果是,它会返回什么?
  • 似乎没有我定义或可以看到的默认成员或属性。它必须是 .Net 自己添加的东西。
【解决方案4】:

frmMain.vb

Dim x As Object
Set x = CreateObject("MyOwn.Object")
Dim f as frmDialog
Set f = New frmDialog
f.SetMyOwnObject x

frmDialog

Dim y As Object
Public Sub SetMyOwnObject(ByRef paramX As Object)
  Set y = paramX
End Sub

当您使用 CreateObject 时,您创建的是对象而不是变体。 当你传递一个对象时,通常你使用 ByRef。

【讨论】:

  • 以上代码生成编译器错误,“ByRef 参数类型不匹配”。
  • 您是否按照他的建议更新了SetMyOwnObject 的签名?
  • @ssorrell:如果您传递给SetMyOwnObject 的变量不是Dim'ed 作为对象,就会发生这种情况。 ByRef 要求传入参数的类型与声明 ByRef 参数的类型相匹配,除非 ByRef 参数声明为 Variant
  • 恕我直言,在 VB6 中使用 ByRef 的理由并不多。如果传递了一个对象实例ByRef,则被调用的方法可以更改对象指向的内容。传递对象ByVal 更安全。调用方法获取对象引用的副本,因此不能将对象重新分配给完全不同的对象,但仍可以更改对象的状态。当我特别需要out 参数时,我只会使用ByRef
  • @Mike Spross:我明白你的观点。但是传递一个对象 ByVal 在我的脑海中似乎是一个糟糕的概念。我意识到它做了什么,它实际上并没有复制对象只是指向对象的指针。但我仍然将 ByVal 视为副本,因此仅将 ByRef 用于对象。这样我就知道当我修改对象时,这些更改将传递给被调用者。在这种情况下,我很少重新分配 paramX。在进行更改之前,我会将其分配给局部变量。我猜我们有不同的编码方式。
猜你喜欢
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 2018-06-16
  • 2016-10-06
  • 2022-01-19
  • 2011-11-12
相关资源
最近更新 更多