patternMinor
Early Binding with Generics
Viewed 0 times
withearlygenericsbinding
Problem
I have a class which takes the method address and arguments, and executes it later when told to do so.
Here is some tester code:
All this works with
The
' 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 ClassHere 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 ClassAll this works with
OPTION STRICT OFFThe
WorkItem class obviously doesn't work with `Solution
-
You're working with delegates so the
-
Don't use
-
Declare your arrays in a .net fashion. The type should be
-
All non-public fields should be in lowerCamelCase.
-
There's no need to apply the
Apply all the fixes allows you to perform a dynamic invoke.
Alternative solution
Another approach would be to wrap the delegate in a parameterless action.
For old compilers
You're working with delegates so the
Action variable should be declared as Delegate. Please note that you need to enclose the type in square brackets as Delegate is a reserved word.-
Don't use
Dim in class-scoped variables, instead apply the access level.-
Declare your arrays in a .net fashion. The type should be
Object().-
All non-public fields should be in lowerCamelCase.
-
There's no need to apply the
Overloads modifier as you're not redeclaring any existing methods.Apply all the fixes allows you to perform a dynamic invoke.
Public Class WorkItem
Private action As [Delegate]
Private args As Object()
Public Sub [Set](action As Action)
Me.SetArgs(action)
End Sub
Public Sub [Set](Of T)(action As Action(Of T), arg As T)
Me.SetArgs(action, arg)
End Sub
Public Sub [Set](Of T1, T2)(action As Action(Of T1, T2), arg1 As T1, arg2 As T2)
Me.SetArgs(action, arg1, arg2)
End Sub
Private Sub SetArgs(ByVal action As [Delegate], ParamArray args As Object())
Me.action = action
Me.args = args
End Sub
Public Sub Execute()
Me.action.DynamicInvoke(Me.args)
End Sub
End ClassAlternative solution
Another approach would be to wrap the delegate in a parameterless action.
Public Class WorkItem
Private method As Action
Public Sub [Set](Of T)(action As Action(Of T), arg As T)
Me.method = New Action(Sub() action.Invoke(arg))
End Sub
Public Sub [Set](Of T1, T2)(action As Action(Of T1, T2), arg1 As T1, arg2 As T2)
Me.method = New Action(Sub() action.Invoke(arg1, arg2))
End Sub
Public Sub [Set](Of T1, T2, T3)(action As Action(Of T1, T2, T3), arg1 As T1, arg2 As T2, arg3 As T3)
Me.method = New Action(Sub() action.Invoke(arg1, arg2, arg3))
End Sub
Public Sub Execute()
Me.method.Invoke()
End Sub
End ClassFor old compilers
Public Delegate Sub Action()
Public Delegate Sub Action(Of T)(ByVal obj As T)
Public Delegate Sub Action(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2)
Public Delegate Sub Action(Of T1, T2, T3)(ByVal arg1 As T1, ByVal arg2 As T2, ByVal arg3 As T3)
Public Class WorkItem
Private Class Closure(Of T)
Public action As Action(Of T)
Public arg As T
Public Sub Invoke()
Me.action.Invoke(Me.arg)
End Sub
End Class
Private Class Closure(Of T1, T2)
Public action As Action(Of T1, T2)
Public arg1 As T1
Public arg2 As T2
Public Sub Invoke()
Me.action.Invoke(Me.arg1, Me.arg2)
End Sub
End Class
Private Class Closure(Of T1, T2, T3)
Public action As Action(Of T1, T2, T3)
Public arg1 As T1
Public arg2 As T2
Public arg3 As T3
Public Sub Invoke()
Me.action.Invoke(Me.arg1, Me.arg2, Me.arg3)
End Sub
End Class
Private method As Action
Public Sub [Set](Of T)(ByVal action As Action(Of T), ByVal arg As T)
Dim closure As New Closure(Of T)
closure.action = action
closure.arg = arg
Me.method = New Action(AddressOf closure.Invoke)
End Sub
Public Sub [Set](Of T1, T2)(ByVal action As Action(Of T1, T2), ByVal arg1 As T1, ByVal arg2 As T2)
Dim closure As New Closure(Of T1, T2)
closure.action = action
closure.arg1 = arg1
closure.arg2 = arg2
Me.method = New Action(AddressOf closure.Invoke)
End Sub
Public Sub [Set](Of T1, T2, T3)(ByVal action As Action(Of T1, T2, T3), ByVal arg1 As T1, ByVal arg2 As T2, ByVal arg3 As T3)
Dim closure As New Closure(Of T1, T2, T3)
closure.action = action
closure.arg1 = arg1
closure.arg2 = arg2
closure.arg3 = arg3
Me.method = New Action(AddressOf closure.Invoke)
End Sub
Public Sub Execute()
Me.method.Invoke()
End Sub
End ClassCode Snippets
Public Class WorkItem
Private action As [Delegate]
Private args As Object()
Public Sub [Set](action As Action)
Me.SetArgs(action)
End Sub
Public Sub [Set](Of T)(action As Action(Of T), arg As T)
Me.SetArgs(action, arg)
End Sub
Public Sub [Set](Of T1, T2)(action As Action(Of T1, T2), arg1 As T1, arg2 As T2)
Me.SetArgs(action, arg1, arg2)
End Sub
Private Sub SetArgs(ByVal action As [Delegate], ParamArray args As Object())
Me.action = action
Me.args = args
End Sub
Public Sub Execute()
Me.action.DynamicInvoke(Me.args)
End Sub
End ClassPublic Class WorkItem
Private method As Action
Public Sub [Set](Of T)(action As Action(Of T), arg As T)
Me.method = New Action(Sub() action.Invoke(arg))
End Sub
Public Sub [Set](Of T1, T2)(action As Action(Of T1, T2), arg1 As T1, arg2 As T2)
Me.method = New Action(Sub() action.Invoke(arg1, arg2))
End Sub
Public Sub [Set](Of T1, T2, T3)(action As Action(Of T1, T2, T3), arg1 As T1, arg2 As T2, arg3 As T3)
Me.method = New Action(Sub() action.Invoke(arg1, arg2, arg3))
End Sub
Public Sub Execute()
Me.method.Invoke()
End Sub
End ClassPublic Delegate Sub Action()
Public Delegate Sub Action(Of T)(ByVal obj As T)
Public Delegate Sub Action(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2)
Public Delegate Sub Action(Of T1, T2, T3)(ByVal arg1 As T1, ByVal arg2 As T2, ByVal arg3 As T3)
Public Class WorkItem
Private Class Closure(Of T)
Public action As Action(Of T)
Public arg As T
Public Sub Invoke()
Me.action.Invoke(Me.arg)
End Sub
End Class
Private Class Closure(Of T1, T2)
Public action As Action(Of T1, T2)
Public arg1 As T1
Public arg2 As T2
Public Sub Invoke()
Me.action.Invoke(Me.arg1, Me.arg2)
End Sub
End Class
Private Class Closure(Of T1, T2, T3)
Public action As Action(Of T1, T2, T3)
Public arg1 As T1
Public arg2 As T2
Public arg3 As T3
Public Sub Invoke()
Me.action.Invoke(Me.arg1, Me.arg2, Me.arg3)
End Sub
End Class
Private method As Action
Public Sub [Set](Of T)(ByVal action As Action(Of T), ByVal arg As T)
Dim closure As New Closure(Of T)
closure.action = action
closure.arg = arg
Me.method = New Action(AddressOf closure.Invoke)
End Sub
Public Sub [Set](Of T1, T2)(ByVal action As Action(Of T1, T2), ByVal arg1 As T1, ByVal arg2 As T2)
Dim closure As New Closure(Of T1, T2)
closure.action = action
closure.arg1 = arg1
closure.arg2 = arg2
Me.method = New Action(AddressOf closure.Invoke)
End Sub
Public Sub [Set](Of T1, T2, T3)(ByVal action As Action(Of T1, T2, T3), ByVal arg1 As T1, ByVal arg2 As T2, ByVal arg3 As T3)
Dim closure As New Closure(Of T1, T2, T3)
closure.action = action
closure.arg1 = arg1
closure.arg2 = arg2
closure.arg3 = arg3
Me.method = New Action(AddressOf closure.Invoke)
End Sub
Public Sub Execute()
Me.method.Invoke()
End Sub
End ClassContext
StackExchange Code Review Q#106709, answer score: 5
Revisions (0)
No revisions yet.