excel vba: специальные типы - функции как аргументы функций - PullRequest
19 голосов
/ 13 июля 2009

Специального типа для функций в VBA нет. Мне трудно понять, как добавлять функции в качестве аргументов к функциям в Excel VBA.

Я пытаюсь сделать что-то вроде этого:

function f(g as function, x as string) as string
        f = g(x)
end function

В настоящее время у меня есть группа маленьких функций, которые все повторяются, но с одним вызовом определенной функции.

Ответы [ 3 ]

19 голосов
/ 21 ноября 2012

Поскольку VBA имеет свои корни в интерактивном языке, он всегда мог выполнять текст:

function f(g as string, x as string) as string
        f = application.run(g,x)
end function

MyStringA = f("functionA",string1)
MyStringB = f("functionB",string1)

Изменить, чтобы добавить: Я думаю, что в текущих версиях Excel приложение (Excel) может «запускать» только то, что можно отобразить в ячейке электронной таблицы. Так что это означает функции, а не подпрограммы. Чтобы выполнить подпрограмму, оберните ее в оболочку функции:

function functionA(x as string)
    Call MySubA(x)
end function
16 голосов
/ 13 июля 2009

Из вашего кода функция g принимает строковый параметр и возвращает строку. Я предлагаю вам создать модуль класса IStringFunction, который будет действовать как определение интерфейса, который будут поддерживать все функции, таким образом:

Модуль класса: IStringFunction

Public Function Evaluate(ByVal s As String) As String
End Function

Затем создайте пару примеров функций, реализующих этот интерфейс:

Модуль класса: HelloStringFunction

Implements IStringFunction

Public Function IStringFunction_Evaluate(ByVal s As String) As String
    IStringFunction_Evaluate = "hello " & s
End Function

Модуль класса: GoodbyeStringFunction

Implements IStringFunction

Public Function IStringFunction_Evaluate(ByVal s As String) As String
    IStringFunction_Evaluate = "goodbye " & s
End Function

... и, наконец, тестовый код для выполнения функций:

(Стандартный) Модуль: Тест

Sub Test()

    Dim oHello As New HelloStringFunction
    Dim oGoodbye As New GoodbyeStringFunction

    MsgBox Evaluate(oHello, "gary")
    MsgBox Evaluate(oGoodbye, "gary")

End Sub

Private Function Evaluate(ByVal f As IStringFunction, ByVal arg As String) As String
    Evaluate = f.Evaluate(arg)
End Function

Обратите внимание, что класс, реализующий интерфейс, должен иметь методы с именем <Interface>_<Method>, как в примере выше, а не просто <Method>, как вы ожидаете.

Загрузите простой демо или промежуточный демо здесь

0 голосов
/ 07 марта 2018

Можно передать функцию в качестве аргумента и получить именно то поведение, которое вам нужно, но это немного глупо. Это достигается путем использования свойства класса по умолчанию

Создайте класс myFunction, содержащий вашу функцию

Public Function sayHi(ByVal s As String) As String
    sayHi = "Hi " & s
End Function

Экспортируйте его и откройте файл .cls в текстовом редакторе

Вы должны увидеть где-нибудь в файле строку, определяющую вашу функцию

Public Function sayHi(ByVal s As String) As String

Под ним добавьте строку Attribute Value.VB_UserMemId = 0, чтобы теперь она выглядела так:

Public Function sayHi(ByVal s As String) As String
Attribute Value.VB_UserMemId = 0
    sayHi = "Hi " & s
End Function

Что вы здесь сделали, так это отметили sayHi как свойство по умолчанию класса. Теперь вы можете вызывать функцию только объектом класса class(args), а не class.function(args)

Сохраните исправленный файл и импортируйте его в свой проект VBA

Тестовый модуль

Sub test()
    Dim parameterFunction As Object         'this is what we'll be passing to our routine
    Set parameterFunction = New myFunction  'create instance of the function object
    MsgBox f(parameterFunction, "Greedo")
End Sub

Function f(ByVal g As Object, ByVal x As String) As String
        f = g(x)
End Function

* NB, таким образом, вы можете передать любую функцию; но вместо этого вы можете указать ByVal g As IStringFunction, чтобы получить только подмножество с правильным интерфейсом согласно ответу Гэри МакГилла

...