2016-08-05 22 views
0

私はExcel VBAを使用しています。誰も引数の長さの制限を克服する方法について知っていますApplication.Run()? (または、同じ仕事を行うことができ、他の機能を提案してください。)私の制約の一部である私の状況に固有30個以上の引数を持つApplication.run

  • は、私は、文字列関数である
  • と呼ばれる関数を指定する必要があります標準モジュール内
  • これは関数なので、戻り値が必要なので、Call()は機能しません。いずれの場合においても

Iは、関数宣言に依存するいくつかの他の機能を書かれているので、私は(例えば、アレイまたはParamArrayの変形に)と呼ばれる関数のパラメータリストを変更する必要はありません。


編集:私は(ただし、元の質問をオフすることができる)、ここで私のプロジェクトの簡易版を提供することができます以下のコメントのいくつかに応じて。事実、30 argの制約を除いて、全体の設計が確立され、円滑に実行されています。

最終的な目標は、=mySpreadSheetFn("calledFn", "para1=abc", "para2=2002", ...)のように呼び出すことができる次のスプレッドシート機能を有効にすることです。

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

mySpreadSheetFn()コールでParamArrayに指定されているデフォルトの引数はそれに応じて置換されます。これは、その宣言かもしれ機能calledFn()を呼び出します。同様に、エンドユーザが使用できるcalledFn2()などがあります。だから、が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 

これは、ユーザインタフェースが必要とされる方法であるため、フロントエンドを変更するには、どんな部屋はほとんどありません。

どのような考えですか?

+1

引数には30個以上の引数が必要ですか? – Rory

+0

あなたは引数が何であるかの例を挙げることができますか?おそらく、セルに値を格納し、単一の範囲を渡すことができます。何か意味のある提案をするためにもっと情報が必要になるでしょう。 – sous2817

+2

これは設計上の問題のように聞こえます。 – Comintern

答えて

1

が、あなたがクラスにメソッドを転送する場合は、すべてがはるかに簡単になり:

クラス "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 
+0

これは実際に私が使用したメソッドですが、CallByNameでparamsを直接使用することはできません。それはこの質問のおかげです:[リンク](https://stackoverflow.com/questions/36313575/passing-an-array-of-arguments-to-callbyname-vba) – user90957

1

複数の引数を配列にパックします。あるいは、Xmlファイルや文字列、JSONファイル/文字列、普通のテキストファイルなど、いくつかの引数を何らかのデータドキュメントにパックすることもできます。

0

30個以上のパラメータを持つプロシージャをApplication.Runで呼び出すことに決めた場合は、その関数のシグネチャを一致させるためにトランポリン手順が必要です。配列(または他のパッケージ)でパラメータを取り二prodecureを行い、その後、あまりにも多くのパラメータで1を呼び出しプロシージャにそれを渡す:おそらく少し遅れ

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 
+0

これは 'IHaveTooManyArguments'をメインでハードコーディングする必要があります。これはあまりクリーンではありません(' IHaveTooMany2'などがあると考えてください)。 )。あなたはそれを避ける方法を提案できますか? – user90957

+0

それを避ける方法はありません。 'Application.Run'の関数シグネチャ(1つの必須パラメータに続いて30のオプションのパラメータ) - periodを変更することはできません。 – Comintern

+0

@ user90957 - 私はあなたの編集を見ました(あなたの機能の署名と一致する私の編集を見てください)。このメソッドはまだ動作します(AFAIKは 'Application.Run'を介して' ParamArray'を渡す唯一の方法です)。 – Comintern

関連する問題