2012-01-26 5 views
13

タグ:VBA、VB6ではなく、VB.NETに注意してください。VBAのカスタムコールバック

これはMS AccessのVBAに固有です。私は "Enumerable"と呼ばれるモジュールにメソッドのコレクションを構築しました。これは、.NETのEnumerableクラスとインターフェイスを彷彿させる多くのことを行います。私が実装したいのは、.NETのEnumerable.Select methodに類似したForEachメソッドです。

Application.Runメソッドを使用して各要素の関数を呼び出すバージョンを作成しましたが、Application.Runはユーザー定義のメソッドでのみ機能します。たとえば、次のように動作します。

' User-defined wrapper function: 
Public Function MyReplace(_ 
    Expression As String, Find As String, StrReplace As String, _ 
    Optional Start As Long = 1, _ 
    Optional Count As Long = 1, _ 
    Optional Compare As VbCompareMethod = vbBinaryCompare) 
    MyReplace = Replace(Expression, Find, StrReplace, Start, Count, Compare) 
End Function 

' Using Application.Run to call a method by name 
Public Sub RunTest() 
    Debug.Print Run("MyReplace", "Input", "In", "Out") 
End Sub 

RunTestは「出力」を期待どおりに出力します。以下は動作しません:「クラスがオートメーションをサポートしていないか、予測したインターフェースをサポートしていません」:

Debug.Print Run("Replace", "Input", "In", "Out") 

これは、実行時エラー430がスローされます。これは、Application.Runがユーザー定義のメソッドに対してのみ機能することをドキュメントに記述しているため、予想されます。

VBAにはAddressOf演算子がありますが、これは外部API関数に関数ポインタを渡すときにのみ機能します。 AddressOfを使用して作成された関数ポインタは、VBAでは消耗しません。ここでも、これはドキュメントに記載されています(または、たとえばVBA - CallBacks = Few Cents Less Than A Dollar?を参照)。

変数を使用してメソッドを識別して呼び出す方法はありますか?または、私のコールバックの試みは、Application.Runメソッドを介してユーザー定義の関数に限定されますか?

+4

addressofを使用することができるが、VBAはクラスをサポートしているので、インタフェースベースのコールバックは問題ありません。 'sub something(arg as string、myCallBackはIWhatever)... myCallBack.call(...)'あなたのメソッドをクラスに入れ、 "CallByName"という名前で呼び出すことができます。動的な引数の数、代わりのものhttp://www.devx.com/tips/Tip/15422 –

+0

私はあなたが実際に助けが必要なものについて少し混乱しています。あなたの最初の段落は 'For For ...それぞれの 'しかし、あなたの質問の残りの部分は、' Application.Run'をVBA関数で使用しようとしていることについて話しています。 – mischab1

+1

@ mischab1 - .NET IEnumerable拡張メソッドのいずれかを見てください。ほとんどの場合、コレクションの各メンバーで実行するコールバックを提供します。私はVBAで同じことをしようとしています。 VBAには代理人や関数ポインタなどはありません。私はApplication.Runを代わりに使用しましたが、適用範囲が限られています。 –

答えて

5

週には他の答えは...解決のために、ここで私が思い付くことが最高だ:

  1. 私はCallByNameの呼び出しのために個々の引数にParamArrayはを解決するヘルパーモジュールを構築しました。 ParamArrayをCallByNameに渡すと、すべての引数が単一の実際のArrayにマッシュされ、呼び出すメソッドの最初の引数に渡されます。
  2. 私は2つのForEachメソッドを構築しました.1つはApplication.Runを呼び出し、もう1つはCallByNameを呼び出します。質問に記載されているように、Application.Runは、ユーザー定義のグローバル(パブリックモジュール)メソッドに対してのみ機能します。次に、CallByNameはインスタンスメソッドでのみ機能し、オブジェクト引数が必要です。

それでも、組み込みのグローバルメソッド(例:Trim())を名前で直接呼び出すことができません。そのため私の問題を回避するには、ちょうど例えば、組み込みのグローバルメソッドを呼び出し、ユーザー定義のラッパーメソッドを構築することです:

Public Function FLeft(_ 
    str As String, _ 
    Length As Long) As String 
    FLeft = Left(str, Length) 
End Function 

Public Function FLTrim(_ 
    str As String) As String 
    FLTrim = LTrim(str) 
End Function 

Public Function FRight(_ 
    str As String, _ 
    Length As Long) As String 
    FRight = Right(str, Length) 
End Function 

...etc... 

のように、私は今のことを行うためにこれらを使用することができます:あなたは文句を言わない

' Trim all the strings in an array of strings 
trimmedArray = ForEachRun(rawArray, "FTrim") 

' Use RegExp to replace stuff in all the elements of an array 
' --> Remove periods that aren't between numbers 
Dim rx As New RegExp 
rx.Pattern = "(^|\D)\.(\D|$)" 
rx.Global = True 
resultArray = ForEachCallByName(inputArray, rx, "Replace", VbMethod, "$1 $2") 
+0

あなたは、 'FLTrim' here' trimmedArray = ForEachRun(rawArray、 "FTrim") 'を意味しますか? – bonCodigo

+1

@bonCodigoいいえ、「トリム」と「LTrim」は別々のVBA機能です。上のコードでは 'LTrim'のラッパーの例を示し、下の例では' Trim'のラッパーを使用しています。 –

+0

私はいくつかの代替提案をしていますが、依然として質問への回答に興味がありますか? – Blackhawk

関連する問題