Application.run有超过30个参数

时间:2016-08-05 17:14:12

标签: excel-vba vba excel

我正在使用Excel VBA。有没有人知道克服Application.Run()的参数长度限制的方法? (或者请建议可以完成同样工作的其他功能。)

根据我的情况,我的一些限制是:

  • 我需要将被调用的函数指定为字符串
  • 该功能在标准模块中
  • 这是一个函数,需要返回值,因此Call()将不起作用。

在任何情况下,我都不希望更改被调用函数的参数列表(例如,变量数组或ParamArray),因为我已经编写了一些依赖于函数声明的其他函数。

编辑:为了回应下面的一些评论,我可以在这里提供我的项目的简化版本(虽然可能不是原始问题)。事实上,除了30-arg约束外,整个设计已经建立并且运行顺畅。

最终目标是启用以下电子表格功能,可以像=mySpreadSheetFn("calledFn", "para1=abc", "para2=2002", ...)一样调用。这将调用函数calledFn(),其声明可能是:

Function calledFn(Optional para1 As String = "P1", _ Optional para2 As Integer = 202, _ Optional para3 As Boolean = True)

并且相应地替换默认参数,如ParamArray调用中的mySpreadSheetFn()所指定。同样,最终用户可以使用calledFn2()等。因此,Application.Run()内必须有mySpreadSheetFn()


以下是函数定义:

Type paramInfo
    Val As Variant
    dataType As String 'can be Enum but let's forget it for this purpose
End Type

Function mySpreadSheetFunction(fnName As String, ParamArray otherParams())

Dim fnParams As Scripting.Dictionary
' getFnDefaultParams(fn): return the defaults and data types of fn's params
'   as a Dictionary. Each item is of type paramInfo (see above)
Set fnParams = getFnParams(fnName)

' For each specified arg check whether it exists for the function.
' If so, replaces the default value with the input value.
' If not exist, then just ignore it
' The problem is really not with this part so just know 
'    we have all the parameters resolved after the for-loop
For i = LBound(otherParams) To UBound(otherParams)
    Dim myKey As String
    myKey = Split(otherParams(i), "=")(0)
    If fnParams.Exists(myKey) Then
        ' parseParam() converts the input string into required data type
        fnParams(myKey).Val = parseParam(Split(otherParams(i), "=", 2)(1), _
                              fnParams(myKey).DataType _
                              )
    End If
Next

' Here is the issue since the call cannot go beyond 30 args
Dim lb As Integer: lb = LBound(fnParams)
Select Case UBound(fnParams) - LBound(fnParams) + 1
Case 1: Application.Run fnName, fnParams(lb).Val
Case 2: Application.Run fnName, fnParams(lb).Val, fnParams(lb + 1).Val
' Omitted, goes until Case 30
' What to do with Case 31??
End Select

' Some other operations for each call

End Function

' An example of function that can be called by the above mySpreadSheetFn()
Function calledFn(Optional para1 As String = "P1", _ 
    Optional para2 As Integer = 202, _ 
    Optional para3 As Boolean = True)

' needs to return value
calledFn = para1 & para2 * 1000

 End Function

几乎没有任何改变前端的空间,因为这就是用户界面的需求。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

可能有点晚了,但如果你把方法转移到一个班级,一切都变得容易了:

班级“c1”

Public Sub IHaveTooManyArguments(ParamArray params())
    Debug.Print "Refactor me!"
End Sub

模块“主要”

Public Sub CallIHaveTooManyArguments(fnName As String, ParamArray params())
    Dim o as new c1
    CallByName o, fnName, VbMethod, params
End Sub

答案 1 :(得分:1)

将几个参数打包到数组中。或者将几个参数打包到某种数据文档中,比如Xml文件/字符串,JSON文件/字符串或普通文本文件。

答案 2 :(得分:0)

如果您决定通过Application.Run调用超过30个参数的过程,则您需要一个蹦床程序才能匹配其功能签名。制作第二个prodecure,它接受数组(或其他一些包)中的参数,然后将其传递给 second 过程,该过程调用参数太多的过程:

Sub Test()
    Dim args As Variant
    args = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, _
                 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, _
                 31, 32)
    Application.Run "ToManyArgsTrampoline", "fnName", args
End Sub

Sub ToManyArgsTrampoline(fnName As String, args() As Variant)
    If UBound(args) = 31 Then
        IHaveTooManyArguments fnName, args(0), args(1), args(2), args(3), args(4), args(5), _
                              args(6), args(7), args(8), args(9), args(10), args(11), _
                              args(12), args(13), args(14), args(15), args(16), args(17), _
                              args(18), args(19), args(20), args(21), args(22), args(23), _
                              args(24), args(25), args(26), args(27), args(28), args(29), _
                              args(30), args(31)
    End If
End Sub

Sub IHaveTooManyArguments(fnName As String, ParamArray otherparams())
    Debug.Print "Refactor me!"
End Sub