2009-07-13 6 views
17

Il n'y a pas de type spécial pour les fonctions dans VBA. Il est difficile pour moi de voir comment ajouter des fonctions comme arguments aux fonctions dans Excel VBA.excel vba: Types spéciaux - Fonctions comme arguments de fonctions

Ce que je suis en train d'accomplir est quelque chose comme ceci:

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

Actuellement, j'ai un groupe de petites fonctions tout se répéter, mais avec un appel à une fonction spécifique.

Répondre

13

De votre code, la fonction g prend un paramètre string et renvoie une chaîne. Je vous suggère de créer un module de classe appelé IStringFunction à agir comme la définition d'une interface que toutes les fonctions soutiendront ainsi:

Module Classe: IStringFunction

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

Ensuite, créez deux fonctions par exemple la mise en œuvre de cette interface:

Module de classe: HelloStringFunction

Implements IStringFunction 

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

Module Classe: GoodbyeStringFunction

Implements IStringFunction 

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

... et enfin, un code de test pour exercer les fonctions:

(Standard) Module: Test

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 

Remarque que la classe implémentant l'interface doit avoir des méthodes nommées <Interface>_<Method> comme dans l'exemple ci-dessus, pas seulement <Method> comme on s'y attendrait.

Téléchargez le simple demo ou intermediate demo ici

+1

Cela ne l'aide pas vraiment, car il doit encore écrire une fonction d'évaluation séparée pour chaque classe. – Treb

+0

@Treb: peut-être que je ne comprends pas la question, mais je ne vois pas ce que vous voulez dire. Chaque classe représente une fonction différente, donc bien sûr, il doit avoir une fonction d'évaluation séparée! Peut-être que si le problème pouvait être réitéré, ce serait plus clair. –

+0

Salut, je pense que c'est la bonne réponse. C'est la façon de le faire en oo-langues, je ne savais juste pas, que les interfaces existent dans VBA - ma faute. Je me souviens avoir vu cette technique la 1ère fois dans * un petit java *. Mais je dois tester la solution proposée. À l'heure actuelle, j'ai reçu un message d'erreur indiquant que l'interface n'était pas implémentée. Fonction publique applique (ByVal tmp As Variant) As Boolean End Function --- Met en œuvre IBooleanFunction Fonction publique applique (ByVal tmp As Variant) As Boolean apply = Application.IsText (tmp) End Function –

15

Depuis VBA a ses racines dans un langage interactif, il a toujours eu la possibilité d'exécuter du texte:

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

c'est sympa mais je ne pense pas que ce soit en fait le même que de passer une fonction aussi loin que les portées vont ... – epeleg

+0

c'est dope! Je vais le prendre, avec ou sans portée idéale. – grisaitis

+0

Dans Excel VBA 2010, cette syntaxe donne une erreur de compilation "Expected: End of statement". Les paramètres nécessitent des parenthèses autour d'eux: f = Application.Run (g, x) –

0

Il est possible de passer une fonction un argument, et obtenez exactement le comportement que vous recherchez, mais c'est un peu hacky. Ceci est réalisé en exploitant la propriété par défaut d'une classe,

Créer une classe myFunction contenant votre fonction

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

Export, et ouvrez le.fichier cls dans un éditeur de texte

Vous devriez voir quelque part dans le fichier, une ligne qui définit votre fonction

Public Function sayHi(ByVal s As String) As String 

dessous, ajoutez la ligne Attribute Value.VB_UserMemId = 0, de sorte qu'il ressemble maintenant à ceci:

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

Ce que vous avez fait ici est de marquer sayHi comme default property de la classe. Maintenant, vous pouvez appeler la fonction par l'objet de classe seul class(args), plutôt que class.function(args)

Enregistrez le fichier modifié et l'importer dans votre projet VBA

module de test

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, cette comme vous pouvez passer n'importe quelle fonction; mais vous pouvez spécifier ByVal g As IStringFunction pour obtenir seulement le sous-ensemble avec l'interface correcte selon Gary McGill's answer