我正在使用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
几乎没有任何改变前端的空间,因为这就是用户界面的需求。
有什么想法吗?
答案 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