Перегрузка функций и UDF в Excel VBA

Я использую Excel VBA для записи UDF. Я хотел бы перегрузить свой собственный UDF несколькими разными версиями, чтобы разные аргументы вызывали разные функции.

Поскольку VBA, похоже, не поддерживает это, может ли кто-нибудь предложить хороший, не запутанный способ достижения той же цели? Должен ли я использовать необязательные аргументы или есть лучший способ?


person Patrick    schedule 15.09.2008    source источник


Ответы (4)


Объявите свои аргументы как Optional Variants, затем вы можете проверить, отсутствуют ли они, используя IsMissing(), или проверить их тип, используя TypeName(), как показано в следующем примере:

Public Function Foo(Optional v As Variant) As Variant

    If IsMissing(v) Then
        Foo = "Missing argument"
    ElseIf TypeName(v) = "String" Then
        Foo = v & " plus one"
    Else
        Foo = v + 1
    End If

End Function

Это можно вызвать из листа как =FOO(), =FOO(число) или =FOO("строка").

person Joel Spolsky    schedule 16.09.2008
comment
Джоэл, неужели мы все должны благодарить вас за наличие Variant в VB/VBA? ;-) - person Yarik; 04.11.2008
comment
Ага. Это было важно для Excel, так как мы чувствовали, что все, что может быть в ячейке электронной таблицы, должно быть в состоянии войти в переменную Basic, иначе простое действие чтения ячейки заняло бы несколько строк кода. - person Joel Spolsky; 08.01.2009
comment
Это скрывает действительные подписи функции. К сожалению, VBA не поддерживает несколько функций с одним и тем же именем и разными типами аргументов. - person IceArdor; 24.07.2014
comment
Очень хорошо. Я забыл о необязательном в функции. Это означает, что вы можете комбинировать обязательные и необязательные переменные в объявлении. - person gavin; 23.09.2020

Если вы можете различать по количеству параметров, то будет работать что-то вроде этого:

Public Function Morph(ParamArray Args())

    Select Case UBound(Args)
    Case -1 '' nothing supplied
        Morph = Morph_NoParams()
    Case 0
        Morph = Morph_One_Param(Args(0))
    Case 1
        Morph = Two_Param_Morph(Args(0), Args(1))
    Case Else
        Morph = CVErr(xlErrRef)
    End Select

End Function

Private Function Morph_NoParams()
    Morph_NoParams = "I'm parameterless"
End Function

Private Function Morph_One_Param(arg)
    Morph_One_Param = "I has a parameter, it's " & arg
End Function

Private Function Two_Param_Morph(arg0, arg1)
    Two_Param_Morph = "I is in 2-params and they is " & arg0 & "," & arg1
End Function

Если единственный способ отличить функцию — по типам, то вам фактически придется делать то, что делают C++ и другие языки с переопределенными функциями, то есть вызывать по сигнатуре. Я бы предложил сделать вызов примерно таким:

Public Function MorphBySig(ParamArray args())

Dim sig As String
Dim idx As Long
Dim MorphInstance As MorphClass

    For idx = LBound(args) To UBound(args)
        sig = sig & TypeName(args(idx))
    Next

    Set MorphInstance = New MorphClass

    MorphBySig = CallByName(MorphInstance, "Morph_" & sig, VbMethod, args)

End Function

и создание класса с рядом методов, соответствующих ожидаемым сигнатурам. Однако вам, вероятно, потребуется некоторая обработка ошибок, и имейте в виду, что распознаваемые типы ограничены: например, даты — это TypeName Double.

person Mike Woodhouse    schedule 16.09.2008

VBA грязный. Я не уверен, что есть простой способ сделать поддельные перегрузки:

В прошлом я либо использовал множество опций, либо использовал разные функции. Например

Foo_DescriptiveName1()

Foo_DescriptiveName2()

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

person theo    schedule 15.09.2008

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

person Jon Fournier    schedule 15.09.2008