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.