Reputation: 5523
If I have a function which may return an object or a primitive type - within it I can do the following to handle those two cases:
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
However, how can I do the same test for the variable where Result
is stored without running the function two times? Eg
Dim myResult As Variant
If IsObject(Result) Then 'test return type of function
Set myResult = Result
Else
myResult = Result
End If
As
myResult = Result 'fails if Result returns object
Set myResult = Result 'fails if Result returns non-object
I am trying to write a series of objects/non objects to an array of variant type
Upvotes: 4
Views: 547
Reputation: 5523
Well one possible solution is to write to the variable directly, by passing it ByRef
. In a standard module:
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
called like
Dim myResult As Variant
LetSet(myResult) = 123 'myResult = 123
LetSet(myResult) = New Collection 'Set myResult = New Collection
Upvotes: 3
Reputation: 112
An alternative solution is to use the Array() function and wrap the function or property output in it.
From memory when I was testing my original solution it didn't work for where the value came from a property of a class only functions. This was an issue when using Interfaces or directly using the property and obtaining variant results.
Note: I don't think it will work for functions/properties returning a UDT or fixed string length.
For your example use the following:
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
Upvotes: 1
Reputation: 112
As an example a snippet from a class, that deals with calling class functions dynamically. It's work in progress for prototyping if can implement some basic VBA Reflection, based off RubberDuck Reflection API. As I'm dynamically calling class and module functions there's no reliable way to know in advance if a primitive or object type will be returned from a function call.
Note I haven't tested the code yet and will need some error handling added to the InvokeMember function.
Greedo's solution is similar expect the function result is a separate parameter by reference, that way can put in the function call eg. CallByName as the second parameter. The first parameter is the variable storing the result called by reference. The function result parameter y is by reference as an array could result and avoids copying the whole array in memory when passed in.
Public Function InvokeMember(ByVal obj As Object, ParamArray args() As Variant) As Variant
Assign InvokeMember, CallByName(obj, Me.FullName, Me.CallType, args)
End Function
In a module, code from 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
Thanks for the question it's helped me solve the same issue avoiding calling the same function twice when dealing with whether it's an object, array or primitive data type being returned.
Upvotes: 1