Delegate Recipe #1Using a Delegate to Loop through a Subroutine.
This is hard to explain in words but the example makes it a little easier to understand.
So lets begin with ForLoop Class.
CODE
Public Class ForLoop
#Region "My Private Varibles"
#Region "Integer Version"
Private m_From_Int As Integer
Private m_UpTo_Int As Integer
Private m_step_Int As Integer
Private m_del_Int As Del_Int_DoFor
#End Region
#Region "Double Version"
Private m_From_Dub As Integer
Private m_UpTo_Dub As Integer
Private m_step_Dub As Integer
Private m_del_Dub As Del_Double_DoFor
#End Region
Private IsIntegerVersion As Boolean = True
#End Region
#Region "Public Delegates"
Public Delegate Sub Del_Int_DoFor(ByVal x As Integer)
Public Delegate Sub Del_Double_DoFor(ByVal x As Double)
#End Region
#Region "Instantiation Routines"
''' <summary>
''' Creates a for-loop that loop over a subroutine.
'''
''' </summary>
''' <param name="_DoWhat">The subroutine to loop over.</param>
''' <param name="_From">Start from value</param>
''' <param name="_To">End at value</param>
''' <param name="_WithAStepOf">Using a step of.</param>
''' <remarks></remarks>
Public Sub New(ByRef _DoWhat As Del_Int_DoFor, ByVal _From As Integer, ByVal _To As Integer, Optional ByVal _WithAStepOf As Integer = Integer.MaxValue)
If _WithAStepOf = Integer.MaxValue Then
Select Case _From.CompareTo(_To)
Case Is < 0 : _WithAStepOf = 1
Case Is > 0 : _WithAStepOf = -1
Case Is = 0 : _WithAStepOf = 1
End Select
End If
Select Case _From.CompareTo(_To)
Case Is < 0
If _WithAStepOf <= 0 Then Throw New Exception("Incrementing For can't have a negative stepping value")
Case Is > 0
If _WithAStepOf >= 0 Then Throw New Exception("Decrementing For can't have a positive stepping value")
End Select
m_From_Int = _From
m_UpTo_Int = _To
m_step_Int = _WithAStepOf
m_del_Int = _DoWhat
End Sub
Public Sub New(ByRef _DoWhat As Del_Double_DoFor, ByVal _From As Double, ByVal _To As Double, Optional ByVal _WithAStepOf As Double = Double.NaN)
IsIntegerVersion = False
If _WithAStepOf = Double.NaN Then
Select Case _From.CompareTo(_To)
Case Is < 0 : _WithAStepOf = 1
Case Is > 0 : _WithAStepOf = -1
Case Is = 0 : _WithAStepOf = 1
End Select
End If
Select Case _From.CompareTo(_To)
Case Is < 0
If _WithAStepOf <= 0 Then Throw New Exception("Incrementing For can't have a negative stepping value")
Case Is = 0
Case Is > 0
If _WithAStepOf >= 0 Then Throw New Exception("Decrementing For can't have a positive stepping value")
End Select
m_From_Dub = _From
m_UpTo_Dub = _To
m_step_Dub = _WithAStepOf
m_del_Dub = _DoWhat
End Sub
#End Region
Public Sub DoForLoop()
' Is it the Integer Version?
If IsIntegerVersion Then
' Yes, then do the integer for-loop
For i As Integer = m_From_Int To m_UpTo_Int Step m_step_Int
m_del_Int.Invoke(i)
Next
Else
' No, then do the double for-loop
For i As Double = m_From_Dub To m_UpTo_Dub Step m_step_Dub
m_del_Int.Invoke(i)
Next
End If
End Sub
Shared Sub ForCode(ByRef _DoWhat As Del_Int_DoFor, ByVal _From As Integer, ByVal _To As Integer, Optional ByVal _WithAStepOf As Integer = Integer.MaxValue)
If _WithAStepOf = Integer.MaxValue Then
Select Case _From.CompareTo(_To)
Case Is < 0 : _WithAStepOf = 1
Case Is > 0 : _WithAStepOf = -1
Case Is = 0 : _WithAStepOf = 1
End Select
End If
Select Case _From.CompareTo(_To)
Case Is < 0
If _WithAStepOf <= 0 Then Throw New Exception("Incrementing For can't have a negative stepping value")
Case Is = 0
Case Is > 0
If _WithAStepOf >= 0 Then Throw New Exception("Decrementing For can't have a positive stepping value")
End Select
For i As Integer = _From To _To Step _WithAStepOf
_DoWhat.Invoke(i)
Next
End Sub
Shared Sub ForCode(ByRef _DoWhat As Del_Double_DoFor, ByVal _From As Double, ByVal _To As Double, Optional ByVal _WithAStepOf As Double = Double.NaN)
If Double.IsNaN(_WithAStepOf) Then
Select Case _From.CompareTo(_To)
Case Is < 0 : _WithAStepOf = 1
Case Is > 0 : _WithAStepOf = -1
Case Is = 0 : _WithAStepOf = 1
End Select
End If
Select Case _From.CompareTo(_To)
Case Is < 0
If _WithAStepOf <= 0 Then Throw New Exception("Incrementing For can't have a negative stepping value")
Case Is = 0
Case Is > 0
If _WithAStepOf >= 0 Then Throw New Exception("Decrementing For can't have a positive stepping value")
End Select
For i As Double = _From To _To Step _WithAStepOf
_DoWhat.Invoke(i)
Next
End Sub
End Class
With that out the way.
What it does.How often have you written the follow code pattern.
CODE
For i As Integer=0 To 10
SomeSub(i)
Next
What the class lets you do the same on a single line.
CODE
ForLoop.LoopCode(New Del_Int_DoFor(AddressOf SomeSub),0,10)
ForLoop.LoopCode
- The Subroutine
Referred to via the delegate. (In ours it New Del_Int_DoFor(AddressOf SomeSub)) - Begin Loop At
- End Loop At (Inclusive)
- Optional Step Granulity
There is also an overload for looping with Doubles, but if you the delegate needs to be
Del_Double_DoFor.
The Clever StuffNow suppose you want the do the above multiple times, I could copy and paste that line.
But this the clever bit since the it a class, I could define a variable of the class type (ForLoop) and use that.
See:
CODE
Dim My_ZeroToTen_Loop As New ForLoop(New Del_Int_DoFor(AddressOf SomeSub),0,10)
Note: The loop parameters are set in stone now and can not be altered.
What that is effectively doing is storing a forloop in a variable, which can be used and re-used later.
CODE
' Somewhere in my code I now can execute that stored loop.
My_ZeroToTen_Loop.DoLoop
Further ExamplesCODE
Module Module1
Dim rn As New Random
Dim gw(5) As Integer
Dim Div5List As New List(Of Integer)
Sub Main()
' ForLoop.ForCode(AddressOf DivisibleBy5, -50, 50)
ForLoop.ForCode(AddressOf DivisibleBy5, 0, 100)
ForLoop.ForCode(AddressOf AssignRandom, LBound(gw), UBound(gw))
ForLoop.ForCode(AddressOf PrintDub, 0.1, 10.1, 2.5)
Dim RandomAssign As New ForLoop(AddressOf AssignRandom, LBound(gw), UBound(gw))
RandomAssign.DoForLoop()
printlist(gw)
Console.WriteLine()
Console.WriteLine("Effect after Redimming")
ReDim gw(10)
RandomAssign.DoForLoop()
Console.WriteLine()
printlist(gw)
ForLoop.ForCode(AddressOf AssignRandom, LBound(gw), UBound(gw))
printlist(gw)
Console.ReadKey()
End Sub
Private Sub printlist(ByRef c As ICollection)
For Each i In c
Console.WriteLine(i)
Next
End Sub
Private Sub DivisibleBy5(ByVal x As Integer)
If x Mod 5 = 0 Then Div5List.Add(x)
End Sub
Private Sub AssignRandom(ByVal x As Integer)
gw(x) = rn.Next
End Sub
Public Sub PrintDub(ByVal x As Double)
Console.WriteLine("{0} ", x)
End Sub
Private Sub PrintOut(ByVal x As Integer)
' Console.WriteLine("{0} ", x)
Dim c As New ForLoop(New ForLoop.Del_Int_DoFor(AddressOf count), 1, x)
c.DoForLoop()
Console.WriteLine()
End Sub
Private Sub count(ByVal x As Integer)
Console.Write("{0} ", x)
End Sub
End Module
So you have a Delayed Execution & Reuse Weapon to add to your Code Ninja arsenal.
