Записать результат функции в переменную, где результат может быть объектом - PullRequest
0 голосов
/ 28 июня 2018

Если у меня есть функция, которая может возвращать объект или примитивный тип - внутри него я могу сделать следующее для обработки этих двух случаев:

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

Я пытаюсь записать серию объектов / не объектов в массив варианта типа

Ответы [ 3 ]

0 голосов
/ 26 декабря 2018

В качестве примера фрагмент из класса, который имеет дело с динамическим вызовом функций класса. В настоящее время ведется работа по созданию прототипа, если можно реализовать некоторые базовые VBA Reflection, основанные на RubberDuck Reflection API . Поскольку я динамически вызываю функции класса и модуля, нет надежного способа узнать заранее, будет ли примитив или тип объекта возвращаться из вызова функции.

Примечание. Я еще не тестировал код, и мне потребуется некоторая обработка ошибок, добавленная в функцию 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

' 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

Спасибо за вопрос, это помогло мне решить одну и ту же проблему, избегая вызова одной и той же функции дважды при работе с возвращаемым типом объекта, массива или примитивного типа данных.

0 голосов
/ 05 июля 2019

Альтернативное решение - использовать функцию Array () и обернуть в нее вывод функции или свойства.
По памяти, когда я тестировал свое первоначальное решение, оно не работало для того, где значение взято из свойства функций только класса. Эта проблема возникала при использовании интерфейсов или при непосредственном использовании свойства и получении вариантов результатов.
Примечание: я не думаю, что это будет работать для функций / свойств, возвращающих 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
0 голосов
/ 28 июня 2018

Ну, одно из возможных решений - записать в переменную напрямую, передав ей ByRef. Тогда Function не имеет возвращаемого значения, поэтому может стать Sub:

Sub Result(ByRef writeTo As Variant)
    '... get item - the return value
    If IsObject(item) Then
        Set writeTo = item
    Else
        writeTo = item
    End If
End Sub

называется

Dim myResult As Variant
Result myResult 'overwrites whatever writeTo contains
...