Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
VBA-使用某些可选参数有条件地调用函数的变通方法?_Vba - Fatal编程技术网

VBA-使用某些可选参数有条件地调用函数的变通方法?

VBA-使用某些可选参数有条件地调用函数的变通方法?,vba,Vba,考虑一个具有多个可选参数的函数。例如: 函数foo(可选a、可选b、可选c、可选d) 如果我只想在参数不为null或其他测试的情况下调用特定函数(因为函数会在其他情况下引发错误,,除非缺少参数) 例如Collection类。Add方法有3个可选参数。许多自定义类包装这个类——比如创建一个可索引的类“Person”自定义类的Persons或类似的东西。包装器必须处理6种组合:仅添加一个键、添加一个键并在之前指定、添加一个键并在之后指定、不添加键并在之前指定、不添加键并在之后指定、无键和无前/后。

考虑一个具有多个可选参数的函数。例如:

函数foo(可选a、可选b、可选c、可选d)
如果我只想在参数不为null或其他测试的情况下调用特定函数(因为函数会在其他情况下引发错误,,除非缺少参数)

例如Collection类。Add方法有3个可选参数。许多自定义类包装这个类——比如创建一个可索引的类“Person”自定义类的Persons或类似的东西。包装器必须处理6种组合:仅添加一个键、添加一个键并在之前指定、添加一个键并在之后指定、不添加键并在之前指定、不添加键并在之后指定、无键和无前/后。如果向类似于Workbook.Save的东西编写一个包装器,它会变得更糟,因为它有十几个可选参数

我不知道有什么方法可以替代一些繁琐的构造,比如:

如果为空,则
如果b为空,那么
如果c为空,那么
如果d为空,则
食物a、b、c、d
其他的
富a,b,c
如果结束
其他的
如果d为空,则
富a、b、d
其他的
富a,b
如果结束
如果结束
其他的
'... 等
显然,对于每个附加的可选变量,嵌套Ifs的数量和一般代码开销大约是原来的两倍

在.NET中,可以传入System.type.Missing类型,从而使表达式更加简单

就像在C#中一样,它可以像以下一样干净:

foo(a??缺失,b??缺失,c??缺失,d??缺失);
(这表示‘如果a为null,那么传入Missing(或者可能在幕后重构调用本身),一个调用相当于不传入可选参数a的任何内容,等等)

如果实现了它,可以在VBA中使用内嵌iff('IIF(boolean,true,false)')实现等价物

是否有我缺少的VBA解决方案?

(关于编辑:我合并了HarveyFrench对代码的改进)

您可以使其嵌套少一点:

Function foo(Optional a, Optional b, Optional c, Optional d)
    Dim passed As String
    If Not IsMissing(a) Then passed = "a "
    If Not IsMissing(b) Then passed = passed & "b "
    If Not IsMissing(c) Then passed = passed & "c "
    If Not IsMissing(d) Then passed = passed & "d "
    foo = IIf(Len(passed) = 0, "Nothing ", passed) & "passed"
End Function

Function foo_dispatcher(Optional a, Optional b, Optional c, Optional d)
    Dim caseNum As Long
    caseNum = IIf(IsNull(a) Or IsEmpty(a) Or IsMissing(a), 0, 8)
    caseNum = caseNum + IIf(IsNull(b) Or IsEmpty(b) Or IsMissing(b), 0, 4)
    caseNum = caseNum + IIf(IsNull(c) Or IsEmpty(c) Or IsMissing(c), 0, 2)
    caseNum = caseNum + IIf(IsNull(d) Or IsEmpty(d) Or IsMissing(d), 0, 1)

    Select Case caseNum
        Case 0: foo_dispatcher = foo()
        Case 1: foo_dispatcher = foo(, , , d)
        Case 2: foo_dispatcher = foo(, , c)
        Case 3: foo_dispatcher = foo(, , c, d)
        Case 4: foo_dispatcher = foo(, b)
        Case 5: foo_dispatcher = foo(, b, , d)
        Case 6: foo_dispatcher = foo(, b, c)
        Case 7: foo_dispatcher = foo(, b, c, d)
        Case 8: foo_dispatcher = foo(a)
        Case 9: foo_dispatcher = foo(a, , , d)
        Case 10: foo_dispatcher = foo(a, , c)
        Case 11: foo_dispatcher = foo(a, , c, d)
        Case 12: foo_dispatcher = foo(a, b)
        Case 13: foo_dispatcher = foo(a, b, , d)
        Case 14: foo_dispatcher = foo(a, b, c)
        Case 15: foo_dispatcher = foo(a, b, c, d)
    End Select
End Function

Sub test()
    Debug.Print foo_dispatcher(Null, Null, Null, Null)
    Debug.Print foo_dispatcher(Null, 1, Null, 2)
    Debug.Print foo_dispatcher(1, 2, 3, 4)
    Debug.Print foo_dispatcher()
    Debug.Print foo_dispatcher(, 1, , 2)
    Debug.Print foo_dispatcher(a:=1, d:=Null)
End Sub
测试的输出

Nothing passed
b d passed
a b c d passed
Nothing passed
b d passed
a passed
显然,这16种情况下的操作可以根据
foo
的调用约定进行定制(例如,如果需要,您可以调度到
foo(a,d)
,而不是
foo(a,,,d)
)。我没有明确检查所有16例,但似乎都有效。我所做的有些机械。您可以编写分派生成器—该函数采用字符串函数名、所需参数数组、可选参数数组和充当
Null
角色的值,并将分派器返回的值作为字符串,可从即时窗口复制粘贴到代码模块。我曾想过在这里这样做,但作为一名概念验证调度员,这似乎不值得。

约翰·科尔曼的回答是“尽可能好的VBA”

我认为foo_dispatcher还需要对代码进行以下修改(在许多情况下):

测试用例还应该包括

Sub test()
    Debug.Print foo_dispatcher(,,,)
    Debug.Print foo_dispatcher(, 1, , 2)
    Debug.Print foo_dispatcher(a:=1,d:=Null)
End Sub

您是否尝试过使用
ParamArray
?除非每个参数都有不同的类型(整数、布尔值、字符串等)。您想如何知道哪个参数是哪个?您希望如何管理Foo()中的参数?您已经将每个参数定义为变量。因此,您可以使用
IsMissing(var)
函数检查
foo
函数内部是否缺少参数。请参阅:@MaciejLos这是对外部函数的调用(即,不是自定义函数)。我无法控制函数如何处理参数,只能控制传入的参数。缺少参数是可以的,但是如果指定了它,那么它就不能为null/nothing/我能想到的任何我可以在inline if.Hmm中使用的参数-可能你可以通过使用Call by name来解决问题。请在我的答案中查看我的注释。我建议您修改代码以合并我的suggestions@HarveyFrench谢谢你的建议。它要求foo_dispatcher本身的参数现在是
可选的
,这是一个更好的改变
foo_dispatcher(,,,)
是一个语法错误,但是
foo_dispatcher()
工作正常。如果将Null视为缺失或空值,我会感到有点不舒服。我个人认为,如果foo接受变量,它应该将Null作为值传递!很好的代码可以绕过“蹩脚的vba”@HarveyFrench空值就是一个例子,因此我可以突出显示与干净类型的显著区别。与vba相比,缺少使用空值coelescing运算符。最终的解决办法是解决整个“缺失”的愚蠢问题——我自己的类没有一个使用缺失,而是总是使用类型本身的特性(Nothing、Empty、Null等)。实际上,它正在寻找某种方法来避免使用指定的不同可选参数显式设置调用方法的各种组合。考虑到我们必须处理现有的问题,我认为你的回答是一个很好的简化方法。谢谢你,这是一个很好的方法,可以使不雅变得更加简化,并且大大优于嵌套Ifs。我查看了CallByName,但它没有结果,因为它不能处理上下文中的可选参数。VB6似乎有一种方法(使用调用程序),但VBA不能使用它。这是对代码的一个很好的修改。我会把它加进去(最后两个4被预期的2和1取代),我很高兴有人醒了!谢谢你的贡献。请参阅上面我的评论,并将您所说的共同努力标记为“VBA将获得的好处”:
Sub test()
    Debug.Print foo_dispatcher(,,,)
    Debug.Print foo_dispatcher(, 1, , 2)
    Debug.Print foo_dispatcher(a:=1,d:=Null)
End Sub