Devolución de llamada personalizada en VBA
callback (1)
No hay otras respuestas en una semana ... por la resolución, aquí está lo mejor que pude encontrar:
- Creé un módulo auxiliar que resuelve un ParamArray a argumentos individuales por llamar a
CallByName
. Si pasas una ParamArray aCallByName
convertirá todos los argumentos en una únicaArray
real y la pasará al primer argumento del método que intentas invocar. -
ForEach
dos métodosForEach
: uno que invocaApplication.Run
y otro que invocaCallByName
. Como se señala en la pregunta,Application.Run
solo funciona para los métodos globales definidos por el usuario (módulo público). A su vez,CallByName
solo funciona en métodos de instancia y requiere un argumento de objeto.
Eso todavía me deja sin una forma de invocar directamente métodos globales incorporados (como Trim()
) por nombre. Mi solución para eso es crear métodos de contenedor definidos por el usuario que solo llamen al método global incorporado, por ejemplo:
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...
Ahora puedo usar estos para hacer cosas como:
'' 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")
Tenga en cuenta la etiqueta: VBA , no VB6, no VB.NET.
Esto es específico de VBA en MS Access. Construí una colección de métodos en un módulo que llamo "Enumerable". Hace muchas cosas que recuerdan las clases Enumerable y las interfaces en .NET. Una cosa que quiero implementar es un método ForEach, análogo al método .Enumerable de .NET.
Creé una versión que usa el método Application.Run para llamar a una función para cada elemento, pero Application.Run solo funciona con métodos definidos por el usuario. Por ejemplo, los siguientes trabajos:
'' 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 imprime "Salida", como se esperaba. Lo siguiente NO funciona:
Debug.Print Run("Replace", "Input", "In", "Out")
Lanza el error 430 en tiempo de ejecución: "La clase no admite automatización o no admite la interfaz esperada". Esto es esperado, porque la documentación indica que Application.Run solo funciona para los métodos definidos por el usuario.
VBA tiene un operador AddressOf, pero eso solo funciona al pasar punteros a las funciones API externas; los punteros de función creados con AddressOf no son consumibles en VBA. De nuevo, esto se observa en la documentación (o ver, por ejemplo, VBA - CallBacks = ¿Hay pocos centavos menos que un dólar? ).
Entonces, ¿hay alguna otra manera de identificar y llamar a un método usando una variable? ¿O mis intentos de devolución de llamada se limitarán a las funciones definidas por el usuario a través del método Application.Run?