如何在VBA中为Variant分配Variant?

Hei*_*nzi 14 vba types variant

(警告:虽然乍看之下可能看起来像是一个问题,但这不是初学者级别的问题.如果你熟悉"强迫"一词,或者你曾经研究过VBA规范,请继续阅读.)

假设我有一个类型的表达式Variant,我想将它分配给一个变量.听起来很简单吧?

Dim v As Variant

v = SomeMethod()    ' SomeMethod has return type Variant
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果SomeMethod返回一个Object(即VarType为vbObject的Variant),则强制启动并v包含该对象的"简单数据值".换句话说,如果SomeMethod返回对TextBox的引用,v则将包含一个字符串.

显然,解决方案是使用Set:

Dim v As Variant

Set v = SomeMethod()
Run Code Online (Sandbox Code Playgroud)

这不幸的是,如果失败,SomeMethod没有返回一个对象,例如一个字符串,产生类型不匹配错误.

到目前为止,我找到的唯一解决方案是:

Dim v As Variant

If IsObject(SomeMethod()) Then
    Set v = SomeMethod()
Else
    v = SomeMethod()
End If
Run Code Online (Sandbox Code Playgroud)

这有SomeMethod两次打电话的不幸副作用.

没有需要调用SomeMethod两次的解决方案?

Lev*_*han 12

在VBA中,将Variant分配给您不知道它是对象还是基元的变量的唯一方法是将其作为参数传递.

如果你不能重构你的代码,以便将v它作为参数传递给Sub,Function或Let属性(尽管Let这也适用于对象),你总是可以v在模块范围内声明并且只有一个专用的Sub用于保存的目的 - 分配变量:

Private v As Variant

Private Sub SetV(ByVal var As Variant)
    If IsObject(var) Then
        Set v = var
    Else
        v = var
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

与其他地方打电话SetV SomeMethod().

不漂亮,但这是没有召唤SomeMethod()两次或触及其内部运作的唯一方式.


编辑

好吧,我仔细研究了这个,我想我找到了一个更接近你想到的更好的解决方案:

Public Sub LetSet(ByRef variable As Variant, ByVal value As Variant)
    If IsObject(value) Then
        Set variable = value
    Else
        variable = value
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

[...]我猜VBA中没有LetSet v = ...语句

现在有: LetSet v, SomeMethod()

根据类型,您没有需要LetSet变量所需的返回值,而是通过引用传递应该将返回值作为第一个参数保存的变量,以便Sub可以更改其值.

  • 另一种语法是将 `LetSet` 视为(参数)属性,允许您执行 `LetSet(v) = SomeMethod()` - [请参阅此处](https://codereview.stackexchange.com/q/231790/ 146810) 获取代码 (2认同)