1

I have a class which takes the method address and arguments, and executes it later when told to do so.

' need to turn option strict off due to Execute method executing late-bound code
Option Strict Off

Public Class WorkItem
    Private Action As Object
    Private Args() As Object

    Public Overloads Sub [Set](action As Action)
        SetArgs(action)
    End Sub

    Public Overloads Sub [Set](Of T)(action As Action(Of T), arg As T)
        SetArgs(action, arg)
    End Sub

    Public Overloads Sub [Set](Of T1, T2)(action As Action(Of T1, T2), arg1 As T1, arg2 As T2)
        SetArgs(action, arg1, arg2)
    End Sub

    '*** more overloads of [Set] method go here... 

    Private Sub SetArgs(ByVal action As Object, ParamArray args() As Object)
        Me.Action = action
        Me.Args = args
    End Sub

    Public Sub Execute()
        '-- early binding doesn't work
        'DirectCast(Me.Action, Action(Of T)).Invoke(Args(0))  

        '-- this works, but forces me to to keep option strict off
        Select Case Args.Length
            Case 0 : Me.Action.Invoke()
            Case 1 : Me.Action.Invoke(Args(0))
            Case 2 : Me.Action.Invoke(Args(0), Args(1))
            Case 3 : Me.Action.Invoke(Args(0), Args(1), Args(2))
            Case 4 : Me.Action.Invoke(Args(0), Args(1), Args(2), Args(3))
        End Select
    End Sub
End Class

Here is some tester code:

Public Class Form1
    Dim TheTask As WorkItem

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        TheTask = New WorkItem
        TheTask.Set(AddressOf DummyProc, TextBox1)
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        TheTask.Execute()
    End Sub

    Private Sub DummyProc(arg As TextBox)
        Threading.Thread.Sleep(1000)
        Debug.Print("work completed")
    End Sub
End Class

The WorkItem class obviously doesn't work with OPTION STRICT ON, due to the late-bound call in Execute method.

Is there any way I can convert the late-bound call to early binding?

Pradeep Kumar
  • 6,836
  • 4
  • 21
  • 47
  • 1
    why not use delegates? They are made for this kind of activities, no? – A.S.H Oct 02 '15 at 12:41
  • From this code snippet, there's no need for `WorkItem` to know about `Args` - have `WorkItem` just hold an `Action`, and pass it a delegate which invokes the method *with the specific argument*. Then `WorkItem.Execute` is just `Me.Action.Invoke()`. – AakashM Oct 02 '15 at 13:07
  • @A.S.H, I'm ok with delegates as long as the code is generic and independent of the caller. How do I go about it? – Pradeep Kumar Oct 02 '15 at 17:48
  • @AakashM, The `Me.Action.Invoke()` needs one argument for where Action is of type `Action(Of T)`. I may be missing the point completely though. Can you show me how to modify my code for this? – Pradeep Kumar Oct 02 '15 at 17:50
  • My `WorkItem.Action` is declared as `Object` because I don't know in advance how many arguments the method will have. So no idea whether it would be `Action` or `Action(Of T)` or `Action(Of T1, T2)` etc. What I showed above is just the minimal code to reproduce the problem. My actual class has multiple overloads of the `Set` method. They accept `Action`, `Action(Of T)`... etc. – Pradeep Kumar Oct 02 '15 at 18:13
  • Updated the `WorkItem` code in my question so that it gives a better understanding of the problem. – Pradeep Kumar Oct 02 '15 at 18:20
  • I think my question is a better fit for [Code Review](http://codereview.stackexchange.com/), since my code is already working and I'm just trying to improve it. But I don't know how to move this question there. Anyone who can help me with this? – Pradeep Kumar Oct 03 '15 at 11:48
  • 1
    If you want your question to be moved, you can flag it for moderator attention and request a migration. I'd say this question looks good to go and have done that. – Vogel612 Oct 03 '15 at 11:52
  • Okay, for the record... my flag for migration was declined. I'll see if I can pull some strings to get this to Code Review by migration. If all else fails, you can manually cross-post the question – Vogel612 Oct 04 '15 at 17:37

1 Answers1

1

This can be achieved by using delegates. You can declare a delegate that represents a non-generic subroutine, and invoke a representation of that delegate on an object that passed arg as a constructor parameter. I don't know if your solution still needs a generic work item by implementing it like this, but my example still keeps that same setup:

Delegate Sub WorkItem()

Dim TheTask As WorkItem

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    TheTask = AddressOf (New DummyProc(Of TextBox)(TextBox1)).Execute
End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    TheTask.Invoke()
End Sub

Private Class DummyProc(Of T)

    Private ReadOnly _arg As T

    Public Sub New(ByVal arg As T)
        _arg = arg
    End Sub

    Public Sub Execute()
        MessageBox.Show(String.Format("My Arg: {0}", _arg))
        Threading.Thread.Sleep(1000)
        MessageBox.Show("work completed")
    End Sub

End Class
avanek
  • 1,649
  • 12
  • 20
  • The problem is I don't have control over which method is to be executed. It is passed at runtime from user code to the `WorkItem` class. So this method doesn't to solve my problem. – Pradeep Kumar Oct 02 '15 at 18:22