在VBA中向Application.Run传递动态参数 - 错误449参数不可选错误。

8

背景:我正在尝试通过VBA的Application.Run函数动态调用方法并动态传递参数给该方法。这更像是一个概念证明而不是实际用例。

代码:

Public Sub Test()
    Call MethodDynamically("MethodToBeCalled", "This doesnt, work")
End Sub

Public Sub MethodDynamically(MethodName As String, Params As String)
    Application.Run MethodName, Params
End Sub

Public Sub MethodToBeCalled(Param1 As String, Param2 As String)
    Debug.Print Param1 & " " & Param2
End Sub

错误:运行Test方法时,MethodDynamically方法中的Application.Run行收到运行时错误'449':参数不是可选的

期望: 我希望运行Test方法将触发MethodToBeCalled方法,传递This doesntwork作为参数。结果会在立即窗口中显示This doesnt work


1
不足为奇 - 你只向需要两个参数的例程传递了一个参数。 - Rory
你的解决方案是什么,@Rory?如何将一个类This doesntwork作为MethodToBeCalled的两个参数? - noobmaster69
1
使第二个参数变为可选项。 - Lowpar
@Lowpar,这样可以运行,但如果参数是必需的怎么办? - noobmaster69
如果最佳参数为空,则创建默认值。 - Lowpar
@Lowpar 如果我想调用的方法有5个参数呢? - noobmaster69
3个回答

6

这个问题已经有了一个答案,在这里,但考虑到允许MethodDynamically调用其他具有任意数量参数的子程序的示例也是值得考虑的。

解决方案是使用ParamArray来处理未知数量的参数。例如:

Option Explicit

Public Sub Test()
    Call MethodDynamically("MethodToBeCalled1", "This", "works") '<-- 2 args
    Call MethodDynamically("MethodToBeCalled2", "This", "works", "too") '<-- 3 args
    Call MethodDynamically("MethodToBeCalled3", "This", "works", "too", "as well") '<-- 4 args
    Call MethodDynamically("MethodToBeCalled4", "Working", 10, 2, 35) '<-- 4 args; different types
End Sub

Public Sub MethodDynamically(MethodName As String, ParamArray Params() As Variant)
    Application.Run MethodName, Params
End Sub

Public Sub MethodToBeCalled1(Params As Variant)
    Debug.Print Params(0) & " " & Params(1)
End Sub

Public Sub MethodToBeCalled2(Params As Variant)
    Debug.Print Params(0) & " " & Params(1) & " " & Params(2)
End Sub

Public Sub MethodToBeCalled3(Params As Variant)
    Debug.Print Params(0) & " " & Params(1) & " " & Params(2) & " " & Params(3)
End Sub

Public Sub MethodToBeCalled4(Params As Variant)
    Debug.Print Params(0) & " " & CStr((Params(1) ^ Params(2)) + Params(3))
End Sub

输出:

This works
This works too
This works too as well
Working 135

你好 Robin,首先这是一个很棒的答案,在 Excel 中运行得非常完美。我很好奇...为什么我在 Microsoft Access 中运行时会收到“编译错误:无效的 ParamArray 使用”?我注意到我的原始问题是关于 Excel 的,所以这是被接受的答案。 - noobmaster69
不太确定 - 我发现在 ThisWorkbook 中使用 ParamArray 不起作用,但在 Excel 的 模块 中可以正常工作。也许这是一个线索? - Robin Mackenzie
ParamArray是Access Basic中的保留字。将其改为其他名称即可正常工作。 - Harassed Dad
它将在ThisWorkbook中按以下方式工作:动态调用方法(“ThisWorkbook.MethodToBeCalled1”,“This”,“works”) - Mike

1
你有两个选项。
1. 将字符串"This doesn't work"拆分为两个参数。
Public Sub TestThis()
    Call MethodDynamically("MethodToBeCalled", "This doesnt", "work")
End Sub

Public Sub MethodDynamically(MethodName As String, Param1 As String, Param2     As String)
    Application.Run MethodName, Params
End Sub

Public Sub MethodToBeCalled(Param1 As String, Optional Param2 As String)
    Debug.Print Param1 & ", " & Param2
End Sub

或者使用可选参数:
Public Sub TestThis()
    Call MethodDynamically("MethodToBeCalled", "This doesnt, work")
End Sub

Public Sub MethodDynamically(MethodName As String, Params As String)
    Application.Run MethodName, Params
End Sub

Public Sub MethodToBeCalled(Param1 As String, Optional Param2 As String)
    Debug.Print Param1 & ", " & Param2
End Sub

编辑: 试试这个。

Public Sub TestThis()
    Call MethodDynamically("MethodToBeCalled", "This doesnt, work")
End Sub

Public Sub MethodDynamically(MethodName As String, Optional params As String = "")
    If params = "" Then Application.Run MethodName
    Select Case selectParamNumbers(params)
        Case 0
        paramArr = paramSplit(params)
        Application.Run MethodName, paramArr(0)
        Case 1
        paramArr = paramSplit(params)
        Application.Run MethodName, paramArr(0), paramArr(1)
        Case 2
        paramArr = paramSplit(params)
        Application.Run MethodName, paramArr(0), paramArr(1), paramArr(2)
        'And so on...
   End Select
End Sub

Public Function paramSplit(param As String) As Variant
    paramSplit = Split(param, delimiter:=", ")
End Function

Public Function selectParamNumbers(param As String) As Long
    Dim paramAmount() As String
    paramAmount = Split(param, delimiter:=",")
    selectParamNumbers = UBound(paramAmount)
End Function

Public Sub MethodToBeCalled(Param1 As String, Optional Param2 As String)
    Debug.Print Param1 & " " & Param2
End Sub

谢谢David。第一种方法的问题在于它使MethodDynamically方法非常脆弱。如果我想调用的方法有超过2个参数,它就会崩溃。你的第二种方法同样脆弱,因为Param2实际上是空的。MethodDynamically中没有任何内容将work分配给Param2 - noobmaster69
参数是否始终是字符串?如果是,您可以使用选择 case 方法,将您的第一个参数拆分成数组并从数组的 ubound 中进行选择。 - David Feltendal

0
Public Sub Test()
    Call MethodDynamically("MethodToBeCalled", "This doesnt, work")
End Sub

Public Sub MethodDynamically(MethodName As String, Params As String, Optional Params2 As String)
    Application.Run MethodName, Params, Params2
End Sub

Public Sub MethodToBeCalled(Param1 As String, Param2 As String)
    Debug.Print Param1 & "  " & Param2
End Sub

这个答案的问题在于它将 MethodDynamically 与特定数量的参数紧密耦合。如果我调用的下一个方法有5个参数或只有1个参数,该怎么办? - noobmaster69
使用Optional作为参数可以使得如果你有一个要发送的参数,它将与之一起工作,否则它将继续仅使用必需的参数,因此如果下一次你有5个参数,但其他时间只有1个参数,最好使用Optional来处理后四个参数... - Xabier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接