Any way to call a method of a class by name?

B

bz

Hi,

I have the following situation:
a class can be loaded dynamically, and an object can be created from
it (the class implements an interface I know).
The class can have one or several methods which are not defined by the
interface. I don't know their name, but I could know their signature
(for example such method receive a parameter of type UserProfile and
returns bool)
Also, my interface have a method that returns the name (as string) of
such method
For example I can have a code like this

string authMethod = myobject.GetAuthenticationMethod();

now I want to be able to call that method, with a code like this

UserProfile upf = new UserProfile(userID);
bool retValue = CallByName(myobject, authMethod, upf);

How can I do this?

Thanks
 
A

Anthony Jones

bz said:
Hi,

I have the following situation:
a class can be loaded dynamically, and an object can be created from
it (the class implements an interface I know).
The class can have one or several methods which are not defined by the
interface. I don't know their name, but I could know their signature
(for example such method receive a parameter of type UserProfile and
returns bool)
Also, my interface have a method that returns the name (as string) of
such method
For example I can have a code like this

string authMethod = myobject.GetAuthenticationMethod();

now I want to be able to call that method, with a code like this

UserProfile upf = new UserProfile(userID);
bool retValue = CallByName(myobject, authMethod, upf);

How can I do this?

It would make much more sense for your interface to return a delegate for
the function you wish to call. I'll take you throught step by step.

Open a new VB Console project

In Module1 place this class:-

Class UserProfile
Private myUserID As Integer
Public Sub New(ByVal UserID As Integer)
myUserID = UserID
End Sub
Public ReadOnly Property UserID()
Get
Return myUserID
End Get
End Property
End Class

Its just a simulaton UserProfile class.

Now add this line of code to the module:-

Delegate Function BoolUserProfile(ByVal UPF As UserProfile) As Boolean

This is line of code creates a delegate class (derived from
System.Delegate). A delegate can be thought of as a function placeholder.
It defines the expected signature of a function. An instance of such a
delegate class can then be passed a function which it will invoke when told
to. We'll see how to create an instance in later.

Now add this Interface defintiion:-

Interface FuncProvider
Function FetchFunc(ByVal Selector As String) As System.Delegate
End Interface

This is my idea of what your loadable classes ought to implement. The
FetchFunc takes some criteria (I'd just used a string but what ever you
need) and returns the base System.Delegate.

Now add this class:-

Class Implementor
Implements FuncProvider

Private Function FetchFunc(ByVal Selector As String) As System.Delegate _
Implements FuncProvider.FetchFunc
Return New BoolUserProfile(AddressOf DoBoolUserProfile)
End Function

Public Function DoBoolUserProfile(ByVal UPD As UserProfile) As Boolean
Return UPD.UserID = 1
End Function

End Class

This is an example of class you would include in your loadable assembly. I
guess you use reflection to find class that Impement the interface you're
interested in (in my case thats FuncProvider).

This class has a public method that has the expected signature, the
important bit is the code in the FetchFunc implementation:-

Return New BoolUserProfile(AddressOf DoBoolUserProfile)

This creates a new instance of the BoolUserProfile and uses the AddressOf
operator to create an underlying delegate from DoBoolUserProfile method on
the object. N.B. this is an instance method, when called via the delegate
it will have access to the members of the specific instance where it was
created.

This implementation of BoolUserProfile checks whether its UserID is 1 and
returns true if so.

Now in the Sub Main() add this code:-

Dim provider As FuncProvider = New Implementor

Dim upf As New UserProfile(1) 'Change to 2 results in false

Dim bup As BoolUserProfile = DirectCast(provider.FetchFunc("Some
criteria"), _
BoolUserProfile)
Console.WriteLine(bup(upf))

Console.ReadKey()

So now we create an instance of the Implementor and hold a reference to its
FuncProvider interface. Create a new UserProfile object.

We call the FetchFunc passing whatever criteria we need. It will return a
Delegate but we know that in this case it will be a BoolUserProfile delegate
so we cast it up.

Now we can treat the bup delegate variable as if it were a function that
takes a user profile and returns a bool, which here were just writing to the
console.

Of course you could also make your interface return specific delegate types
and create methods for each type on the interface.

This is approach is certainly a lot better than further reflection malarky
you would need to find methods of a specific signature. Whilst doable is
way uglier.
 
J

John Vottero

bz said:
Hi,

I have the following situation:
a class can be loaded dynamically, and an object can be created from
it (the class implements an interface I know).
The class can have one or several methods which are not defined by the
interface. I don't know their name, but I could know their signature
(for example such method receive a parameter of type UserProfile and
returns bool)
Also, my interface have a method that returns the name (as string) of
such method
For example I can have a code like this

string authMethod = myobject.GetAuthenticationMethod();

now I want to be able to call that method, with a code like this

UserProfile upf = new UserProfile(userID);
bool retValue = CallByName(myobject, authMethod, upf);

How can I do this?

MethodInfo mi = upf.GetType().GetMethod(authMethod);
bool retValue = mi.Invoke(upf, myObject);
 
B

bz

Antony,

Thanks for your very detailed answer.
I planned to use such approach (I write it in C# actually, but that's
the same concept), but it does not address exactly my situation
The issue is, I need to write a front end for a BE app already
developed, which I have to "hook"to my frontend.
I don't have the BE app, so I cannot set references in it to its
methods, etc. The system must be very decoupled. I only have access to
some interfaces (like IUserProfile, etc)
And what I need is to be able to configure the "links" between the BE
and my FE in a config file (app.config / web.config), using BE
assembly name, BE class name, BE method, etc
Then the FE load the info from that config, and using reflection
instantiate the class from the assembly and then calls the method.

John,

Thank you for your suggestion, I think it is exactly what I'm looking
for

Regards
Bogdan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top