Note the tag: VBA, not VB6, not VB.NET.
This is specific to VBA in MS Access. I’ve built a collection of methods in an module I call “Enumerable”. It does a lot of things reminiscent of the Enumerable classes and interfaces in .NET. One thing I want to implement is a ForEach method, analagous to the .NET Enumerable.Select method.
I built a version that uses the Application.Run method to call a function for each element, but Application.Run only works with user-defined methods. For example, the following works:
' 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 prints “Output”, as expected. The following does NOT work:
Debug.Print Run("Replace", "Input", "In", "Out")
It throws run-time error 430: “Class does not support Automation or does not support expected interface”. This is expected, because the documentation states that Application.Run only works for user-defined methods.
VBA does have an AddressOf operator, but that only works when passing function pointers to external API functions; function pointers created using AddressOf are not consumable in VBA. Again, this is noted in the documentation (or see for example VBA – CallBacks = Few Cents Less Than A Dollar?).
So is there any other way to identify and call a method using a variable? Or will my callback-ish attempts be limited to user-defined functions via the Application.Run method?
No other answers in a week…for resolution’s sake here’s the best I could come up with:
CallByName. If you pass a ParamArray through toCallByNameit will mash all the arguments into a single, actualArrayand pass that to the first argument in the method you attempt to invoke.ForEachmethods: one that invokesApplication.Run, and another that invokesCallByName. As noted in the question,Application.Runonly works for user-defined global (public module) methods. In turn,CallByNameonly works on instance methods, and requires an object argument.That still leaves me without a way to directly invoke built-in global methods (such as
Trim()) by name. My workaround for that is to build user-defined wrapper methods that just call the built-in global method, for example:I can now use these to do things like: