Dynamically access methods with unkown parameters

Arokh

Centurion
Joined
Apr 11, 2006
Messages
124
Hi

I want to store methods in a List/Arraylist Class with different parameters.
Until now I declared a delegate which has the same parameters as the method to store,
then within a method I declared another variable as the delegate,
then I assigned the address of the method.
Simply put I did this:
Visual Basic:
Class Main
    Delegate Sub Exec(ByVal Code As String)
    Private Sub Test(ByVal Code As String)
        Dim TestSub As New Exec(AddressOf Test)
        TestSub(Code) 'I know it loops, it is just to demonstrate :)
    End Sub
End Class


But now I want to pass methods whose parameters I don't know beforehand and
therefore can't declare a delegate for it.
What I want to be able to do:
Visual Basic:
Class Main 'Would be great if it worked he he
    Dim Methods As List(Of [Delegate])

    Private Sub ProgramStartsHere()
        Methods.Add(AddressOf DoSomething1)
        Methods.Add(AddressOf DoSomething2)
        Methods.Add(AddressOf DoSomething3)

        Methods(0)("bla")
        Methods(1)(5)
        Methods(2)("bla", 5)

    End Sub

    'Random Subs with unkown params
    Private Sub DoSomething1(ByVal Bla As String)
    End Sub
    Private Sub DoSomething2(ByVal bla As Integer)
    End Sub
    Private Sub DoSomething3(ByVal bla As String, ByVal bla2 As Integer)
    End Sub
End Class

Any idea how to pull this off?
 
At the point where the delegate is created, you must have a matching delegate type. In order to create the delegate, the CLR must know the signature of the function, and this means that it needs a delegate type.

DotNet supports late binding with delegates by using the DynamicInvoke method of System.Delegate. This makes things easier.

I whipped up this demo console app which is as close, I think, as possible to what you want. If you run the program you will see the expected output.
Code:
[Color=Blue]Module [/Color]Module1
   [Color=Green] ' Place to store a list of functions
[/Color]    [Color=Blue]Dim [/Color]delegates [Color=Blue]As New[/Color] List([Color=Blue]Of [/Color][Delegate])

    [Color=Blue]Sub [/Color]Main()
       [Color=Green] ' In order to create these delegates, DotNet needs to know the signature.
        ' Otherwise DotNet can't invoke the method. That means we need a delegate type.
        ' This is why you must declare a variable with a delegate type (or cast an "AddressOf"
        ' to a delegate type before using it).
[/Color]        [Color=Blue]Dim [/Color]a [Color=Blue]As [/Color]DelA = [Color=Blue]AddressOf [/Color]Test1
        [Color=Blue]Dim [/Color]b [Color=Blue]As [/Color]DelB = [Color=Blue]AddressOf [/Color]Test2
        [Color=Blue]Dim [/Color]c [Color=Blue]As [/Color]DelC = [Color=Blue]AddressOf [/Color]Test3

       [Color=Green] ' We can then add the delegates to a delegate array.
[/Color]        delegates.AddRange([Color=Blue]New [/Color][Delegate]() {a, b, c})
        [Color=Green]' You can do it without declaring a variable beforehand like so.[/Color]
        delegates.Add([Color=Blue]CType[/Color]([Color=Blue]AddressOf[/Color] Test1, DelA))
        [Color=Green]' And invoke them using late binding.[/Color]
        Console.WriteLine(MakeString(delegates(0).DynamicInvoke()))
        Console.WriteLine(MakeString(delegates(1).DynamicInvoke(5)))
        Console.WriteLine(MakeString(delegates(2).DynamicInvoke("Five")))

        [Color=Green]' Wait for ENTER[/Color]
        Console.ReadLine()

[Color=Blue]    End Sub[/Color]

    [Color=Blue]Function [/Color]MakeString([Color=Blue]ByVal [/Color]obj [Color=Blue]As Object[/Color]) [Color=Blue]As String[/Color]
        [Color=Blue]If [/Color]obj [Color=Blue]Is Nothing Then[/Color]
            [Color=Blue]Return [/Color]"(NULL)"
        [Color=Blue]End If[/Color]

        [Color=Blue]Return [/Color]obj.ToString()
    [Color=Blue]End Function[/Color]

    [Color=Green]'Test delegates[/Color]

    [Color=Blue]Delegate Sub[/Color] DelA()
    [Color=Blue]Delegate Function [/Color]DelB([Color=Blue]ByVal [/Color]x [Color=Blue]As Integer[/Color]) [Color=Blue]As Integer[/Color]
    [Color=Blue]Delegate Function[/Color] DelC([Color=Blue]ByVal [/Color]x [Color=Blue]As String[/Color]) [Color=Blue]As Integer
[/Color]

    [Color=Green]'Test Functions[/Color]

    [Color=Blue]Sub [/Color]Test1()
    [Color=Blue]End Sub[/Color]

    [Color=Blue]Function [/Color]Test2([Color=Blue]ByVal [/Color]x [Color=Blue]As Integer[/Color]) [Color=Blue]As Integer
        Return [/Color]x + 1
    [Color=Blue]End Function[/Color]

    [Color=Blue]Function [/Color]Test3([Color=Blue]ByVal [/Color]x[Color=Blue] As String[/Color])[Color=Blue] As Integer[/Color]
        [Color=Blue]Return [/Color]x.Length
[Color=Blue]    End Function
End Module
[/Color]
 
Worked perfectly.

Just to satisfy my curiosity:
There is no way to create a delegate at runtime?
 
Back
Top