Call a method with a "variable" name

Can I put the name or address of a method in a dictionary, then call that method later by getting it’s address from the dictionary?

My application has lots of reports that display in a viewer window. I’m trying to make the viewer window smarter - so that it can refresh the report. I create an instance of the viewer and pass it a dictionary with the parameters needed for the report. If one of the dictionary values contains the name of a method, can I call that method?

I’m trying to avoid many different viewer windows, or using a long Select/Case statement.

Do you use MBS Plugin?

There we have a CallMethodMBS method which calls a method by name.
You can pass up to three arguments as variants.

Two possibilities come to my mind:
– Introspection
– Delegates

Another idea is a Report subclass. The super raises an event that the subclass handles, and you create, store, and pass around that subclass.

Thanks for the suggestions. Delegates and Introspection get close, but AddressOf won’t take a variable name.

I don’t think subclassing the report will help because I would need a subclass for each type of report. (Each report has a method that creates it.) Easier to go with a long Select/Case.

I’ll take a look at CallMethodMBS. This particular project doesn’t generate any revenue for me (its for a non-profit) so I’m trying to stick with what I already have.

?

Would you be so kind to post a few example code of what you want to do ?

A simple example… I hope this is clear.

I set up the report like this the first time. I use a dictionary for the parameters since each report/method needs different things.

Dim myDict As New Dictionary myDict.Value("Method") = AddressOf myModule.Rpt123 myDict.Value("sql") = "SELECT a, b, c ..." myDict.Value("other") = "foobar" Call myModule.myMethod(myDict)

So far no problem. The dictionary has been passed through to the window displaying the report.

Later when I want to refresh the report, I need to call the method and pass it the dictionary containing the parameters. The Refresh button in the report window needs to do something like this::

Call myDict.Value("Method") (myDict)      --> doesn't compile

I tried setting it up using a Delegate, but need something like this:

[code]Delegate MethodCaller(p As Dictionary)

Dim callMethod As MethodCaller
callMethod = AddressOf myDict.Value(“Method”) --> doesn’t compile[/code]

Dim callMethod As MethodCaller callMethod = myDict.Value("Method")

Elis code gets the method. Then to actually call it…

callMethod.Invoke(myDict)

Call is not the magic word here. It won’t allow you to call a variable instead of a method.
See http://documentation.xojo.com/index.php/call

You cannot say Call Steak instead of Call Cook Steak

What you can do is create a generalized method that takes all the arguments you mention and through some syntactic analisis decides what to do with them.

It seems quite possible to create a Wiz(arg as String) method that will takes the values you describe. You would call it like

Call Wiz(myDict.Value("Method"))

Then you need in the method to look at the content of arg, and for instance if it contains “AddressOf myModule.Rpt123”, call myModule.Rpt123 and return. But what if that method needs arguments ?

If you look at your examples, there is nothing impossible. Well, I don’t know what you want to do with foobar, though.

That is possible, but I feel you are in for a lot of complexity, because what you want to do requires to do somewhat the same as what the Xojo compiler does for you.

You may want to refine the analysis of the processes involved in your app, and use separate methods judiciously designed.

Thank you Eli and Will! To summarize, here is working code for first run and setup:

Dim myDict As New Dictionary myDict.Value("Method") = AddressOf myModule.Rpt123 myDict.Value("sql") = "SELECT a, b, c ..." myDict.Value("other") = "foobar" Call myModule.Rpt123(myDict)
Subsequent refresh:

[code]Delegate MethodCaller(p As Dictionary)

Dim callMethod As MethodCaller
callMethod = myDict.Value(“Method”)
callMethod.Invoke(myDict)[/code]

Personally I’d have a class that represents the entire set up & call rather than using a dictionary

Why ?
Long term expandability & extension - and becuase you have an easier time specializing when you need to

For most calls you can use the main class set up as something like

  Dim myInstance As New MyGenericCallerClass( AddressOf myModule.Rpt123,  "SELECT a, b, c ...",  "foobar")
  Call myModule.Rpt123(myInstance) // not sure about this

and IF / when you need extra parameters or special handling you can make a subclass of MyGenericaCallerClass and use an instance of that new subclass and nothing else changes

In fact I’d probably go so far as to make the INSTANCE do the method invocation and pass in the Viewer window for the specific instance to put its results in

Dim myInstance As New MyGenericCallerClass( AddressOf myModule.Rpt123,  "SELECT a, b, c ...",  "foobar")
myInstance.Execute( myModule.Rpt123 ) // the instance runs its report & generates a result that gets display in the RPT123 window

Again this makes it so every instance invokes things the same way and they simply generate a viewable result that the viewer can display