将函数的结果写入变量,其中结果可以是对象

Write result of function to a variable, where result could be an object

如果我有一个可以 return 对象或基本类型的函数 - 在其中我可以执行以下操作来处理这两种情况:

Function Result() As Variant 'may be object or not
    '... get item - the return value
    If IsObject(item) Then
        Set Result = item
    Else
        Result = item
    End If
End Function

但是,如何在没有运行函数的情况下对存储Result的变量进行两次相同的测试?例如

Dim myResult As Variant
If IsObject(Result) Then 'test return type of function
    Set myResult = Result
Else
    myResult = Result
End If

作为

myResult = Result 'fails if Result returns object
Set myResult = Result 'fails if Result returns non-object

我正在尝试将一系列 objects/non 对象写入变体类型的数组

嗯,一种可能的解决方案是直接写入变量,通过传递它 ByRef。在标准模块中:

Property Let LetSet(ByRef variable As Variant, ByVal value As Variant)
    If IsObject(value) Then
        Set variable = value
    Else
        variable = value
    End If
End Sub

叫得像

Dim myResult As Variant
LetSet(myResult) = 123                'myResult = 123
LetSet(myResult) = New Collection     'Set myResult = New Collection

例如来自 class 的片段,它处理动态调用 class 函数。如果可以基于 RubberDuck Reflection API 实现一些基本的 VBA 反射,原型制作正在进行中。当我动态调用 class 和模块函数时,没有可靠的方法可以提前知道函数调用返回的是原始类型还是对象类型。

请注意,我还没有测试代码,需要在 InvokeMember 函数中添加一些错误处理。

Greedo 的解决方案类似,期望函数结果是一个单独的引用参数,这样可以放入函数调用中,例如。 CallByName 作为第二个参数。第一个参数是存储引用调用结果的变量。函数结果参数 y 通过引用作为数组可能的结果,并避免在传入时将整个数组复制到内存中。

Public Function InvokeMember(ByVal obj As Object, ParamArray args() As Variant) As Variant
    Assign InvokeMember, CallByName(obj, Me.FullName, Me.CallType, args)
End Function

在模块中,来自 VBA Extension Library

的代码
' Assign x to y regardless of object or primitive
Public Sub Assign(ByRef x as Variant, ByRef y as Variant)

    If IsObject(y) Then
        Set x = y
    Else
        x = y
    End If

End Sub

感谢您的提问,它帮助我解决了同样的问题,避免在处理返回的对象、数组或原始数据类型时调用同一个函数两次。

另一种解决方案是使用 Array() 函数并将函数或 属性 输出包装在其中。
根据记忆,当我测试我的原始解决方案时,它不适用于值来自 class 的 属性 的地方。这是使用接口或直接使用 属性 并获得变体结果时的问题。
注意:我认为它不适用于 functions/properties 返回 UDT 或固定字符串长度。

对于您的示例,请使用以下内容:

Dim myResult As Variant
Dim resultOutput as Variant
resultOutput = Array(Result)
If VBA.IsObject(resultOutput(0)) Then
    set myResult = resultOutput(0)
Else
    myResult = resultOutput(0)
End If