2009-07-13 17 views
17

No hay un tipo especial para funciones en VBA. Es difícil para mí ver cómo agregar funciones como argumentos a funciones en Excel VBA.excel vba: Tipos especiales - Funciones como argumentos de funciones

Lo que estoy tratando de lograr es algo como esto:

function f(g as function, x as string) as string 
     f = g(x) 
end function 

Actualmente, tengo un grupo de pequeños todas las funciones que se repiten, pero con una llamada a una función específica.

Respuesta

13

Desde su código, la función g toma un parámetro de cadena y devuelve una cadena. Sugiero crear un módulo de clase llamado IStringFunction para actuar como la definición de una interfaz que todas las funciones apoyarán, por lo tanto:

módulo de clase: IStringFunction

Public Function Evaluate(ByVal s As String) As String 
End Function 

A continuación, crea un par de ejemplos de funciones la implementación de esta interfaz:

módulo de clase: HelloStringFunction

Implements IStringFunction 

Public Function IStringFunction_Evaluate(ByVal s As String) As String 
    IStringFunction_Evaluate = "hello " & s 
End Function 

módulo de clase: GoodbyeStringFunction

Implements IStringFunction 

Public Function IStringFunction_Evaluate(ByVal s As String) As String 
    IStringFunction_Evaluate = "goodbye " & s 
End Function 

... y, finalmente, un código de prueba para ejercer las funciones:

(Estándar) Módulo: Prueba

Sub Test() 

    Dim oHello As New HelloStringFunction 
    Dim oGoodbye As New GoodbyeStringFunction 

    MsgBox Evaluate(oHello, "gary") 
    MsgBox Evaluate(oGoodbye, "gary") 

End Sub 

Private Function Evaluate(ByVal f As IStringFunction, ByVal arg As String) As String 
    Evaluate = f.Evaluate(arg) 
End Function 

Nota que la clase que implementa la interfaz debe tener métodos llamados <Interface>_<Method> como en el ejemplo anterior, no solo <Method> como era de esperar.

Descargar el simple demo o intermediate demo aquí

+1

Eso realmente no lo ayuda, porque todavía tiene que escribir una función de evaluación separada para cada clase. – Treb

+0

@Treb: tal vez no entiendo la pregunta, pero no entiendo a qué te refieres. Cada clase representa una función diferente, ¡así que por supuesto tiene que tener una función de evaluación por separado! Tal vez si el problema pudiera ser reescrito sería más claro. –

+0

Hola, creo que esta es la respuesta correcta. Esta es la manera de hacerlo en oo-languages, simplemente no sabía, que las interfaces existen en VBA - mi culpa. Recuerdo haber visto esta técnica la primera vez en * un poco de java *. Pero tengo que probar la solución propuesta. En este momento recibí un mensaje de error acerca de no implementar la interfaz. Función Pública aplica (tmp ByVal como Variant) As Boolean Función Fin --- Implementa IBooleanFunction Función Pública aplicable (ByVal tmp como variante) As Boolean = aplican Application.IsText (TMP) End Function –

15

Desde VBA tiene sus raíces en un lenguaje interactivo, que siempre ha tenido la capacidad de ejecutar texto:

function f(g as string, x as string) as string 
     f = application.run(g,x) 
end function 

MyStringA = f("functionA",string1) 
MyStringB = f("functionB",string1) 
+0

esto es bueno, pero no creo que en realidad sea lo mismo que pasar una función en cuanto a los alcances van ... – epeleg

+0

que es droga! Lo tomaré, con o sin alcance ideal. – grisaitis

+0

En Excel VBA 2010, esta sintaxis da un error de compilación "Esperado: final de instrucción". Los parámetros necesitan paréntesis a su alrededor: f = Application.Run (g, x) –

0

Es posible pasar una función como un argumento, y obtiene exactamente el comportamiento que busca, pero es un poco hacky. Esto se logra mediante la explotación de la propiedad predeterminada de una clase,

crear una clase que contiene la función myFunction

Public Function sayHi(ByVal s As String) As String 
    sayHi = "Hi " & s 
End Function 

exportarlo, y abra la.archivo cls en un editor de texto

Debe ver en alguna parte del archivo, una línea que define su función

Public Function sayHi(ByVal s As String) As String 

Debajo de ella, añada la línea Attribute Value.VB_UserMemId = 0, por lo que ahora se ve así:

Public Function sayHi(ByVal s As String) As String 
Attribute Value.VB_UserMemId = 0 
    sayHi = "Hi " & s 
End Function 

Lo que ha hecho aquí es marcar sayHi como default property de la clase. Ahora se puede llamar a la función de la clase de objeto solos class(args), en lugar de class.function(args)

Guardar el archivo modificado y la importación en su proyecto de VBA

módulo de prueba

Sub test() 
    Dim parameterFunction As Object   'this is what we'll be passing to our routine 
    Set parameterFunction = New myFunction 'create instance of the function object 
    MsgBox f(parameterFunction, "Greedo") 
End Sub 

Function f(ByVal g As Object, ByVal x As String) As String 
     f = g(x) 
End Function 

* NB, este forma en que puede pasar cualquier función; pero en su lugar puede especificar ByVal g As IStringFunction para obtener solo el subconjunto con la interfaz correcta según Gary McGill's answer

Cuestiones relacionadas