Delegates in VB.NET

Multicast Delegates

Multicast delegates allow you to chain together several functions or subs that are all called together when the delegate is invoked. For the current iteration of the framework, you can't designate the order that the functions are run, only that they are all run, one after another. Let's look at the code for the multicast delegate.

First we add a new sub for our second delegate.

Private Sub WriteToDebug2()
    Debug.WriteLine( "Delegate Wrote To Debug Window 2" )
End Sub

Our declaration of the MySubDelegate stays the same, and here is our new usage code.

Dim del As MyDelSub
Dim del2 As MyDelSub 
Dim delAll As [Delegate]

del = New MyDelSub(AddressOf WriteToDebug)
del2 = New MyDelSub(AddressOf WriteToDebug2)
delAll = MulticastDelegate.Combine(del, del2)
delAll.DynamicInvoke( Nothing ) 

As we examine this code, we see three delegate variables; two for our normal delegates that call our subs and one form the combined other two delegates. We set up our normal delegates as always, one points to WriteToDebug, the other to WriteToDebug2. When we combine the two delegates into our third, we utilize the static function Combine, of the MulticastDelegate class. It has two overloads, one that combines two delegates like we used, and one that takes an array of delegates. Next we invoke all the delegates with the combined delegates DynamicInvoke property, passing in Nothing for its parameter. We could have also passed in an array of objects that would be used for parameters to the invoked subs.

If you check out the declaration of the last sample, you see another huge benefit of delegates. Notice that both del and del2 point to different functions, but are of the same type, MyDelSub. This opens up loads of programming potential. It allows you to point a MyDelSub variable to ANY sub that has the same signature as itself. In our case, it's a simple sub with no parameters. This behavior will let you program more generically. Next we will examine this generic behavior in detail. It works well on both sides of the equation, either invoking a delegate from inside your class or receiving a delegate from outside your class to work upon.

You are already familiar with the concept of having a class invoke a delegate that originates from inside it. Anytime you handle an event from a control you are catching a delegate that has been invoked from inside the control so we won't go into detail about it. Just remember that when you register a function via handles or addhandler, you are telling a delegate somewhere to make sure it calls your function when it's invoked. If you have multiple functions the have handles for the same event, you are just using a multicast delegate.

Let's take a look at some customization with delegates. You can create classes that allow users to input delegates for certain routines. The classes take a list of delegates to call during specific times. This can be used to add different behaviors to your class, such as different sorting routines. This is a more modern and slightly different version of the Visitor design pattern as described in the GOF book.

To start our example, lets take a simple class that represents a dog. It's very simple, with only one method and a define for our delegate.

Public Class Bulldog
	Public Delegate Sub BarkMethod()
	Public Sub DoBark( ByVal BarksToRun As BarkMethod)
		BarksToRun.DynamicInvoke( Nothing )
	End Sub
End Class

The delegate sub BarkMethod is what we will use to create variables from. The sub DoBark takes an instance of the delegate to run.

Now for our test code.

Dim bk1 As Bulldog.BarkMethod
Dim bk2 As Bulldog.BarkMethod
Dim MyDog As Bulldog
MyDog = New Bulldog
bk1 = New Bulldog.BarkMethod(AddressOf Bark1)
bk2 = New Bulldog.BarkMethod(AddressOf Bark2)
MyDog.DoBark(bk1)
MyDog.DoBark(bk2)

We create two delegate variables of the type Bulldog.BarkBethod. We then assign each variable to a sub in our test code, which we see here:

Private Sub Bark1()
    Debug.WriteLine( "Woof Woof" )
End Sub
Private Sub Bark2()
    Debug.WriteLine( "Yip Yip" )
End Sub

The subs simply write to the debug window. As we create and use our dog object, we decide we want to make the dog bark by using Bark1 and then by using Bark2. We simply pass in the correct delegate to the dog object, which calls our external subs to do the work. As you can see, this pattern makes for very easy expansion. If we decide to make the dog talk, then we just add a delegate variable that points to a sub that returns “Hello”.

The next step up would be the need to take multiple delegates for the function instead of the singular bk1 or bk2. To facilitate this you can change the dog class to contain add and remove subs that control an internal delegate of what barks to run. Here is our new dog class.

Public Class Bulldog
Private _Barks As [Delegate]
Public Delegate Sub BarkMethod()
Public Sub DoBark()
	If Not IsNothing(_Barks) Then 'check to see if there is anthing to Invoke
	     _Barks.DynamicInvoke( Nothing )
	End If
End Sub
Public Sub AddBark( ByVal Bark As BarkMethod)
    _Barks = MulticastDelegate.Combine(_Barks, Bark)
End Sub
Public Sub RemoveBark( ByVal Bark As BarkMethod)
    _Barks = MulticastDelegate.Remove(_Barks, Bark)
End Sub
End Class

You can see that we have added a private property, _Barks, to keep track of our delegates to call. Our AddBark and RemoveBark subs use static functions of the MulticastDelegate to add and remove delegate. These functions could also be easily overloaded to take an array of BarkMethods instead of single instances.

Here is our new test code.

Dim bk1 As Bulldog.BarkMethod
Dim bk2 As Bulldog.BarkMethod
Dim MyDog As Bulldog
MyDog = New Bulldog
bk1 = New Bulldog.BarkMethod(AddressOf Bark1)
bk2 = New Bulldog.BarkMethod(AddressOf Bark2)
MyDog.AddBark(bk1)
MyDog.AddBark(bk2)
MyDog.DoBark()
MyDog.RemoveBark(bk2)
MyDog.DoBark()

Our Bark1 and Bark2 subs didn't change, so I don't show them. In the test code, we create our normal two delegates and then, using our new methods, add them to our dog class. After we make the dog bark, we remove the bk2 variable from the dog and make him bark again. The output is as follows:

  Woof Woof
  Yip Yip
  Woof Woof

You might also like...

Comments

About the author

John Spano United States

John Spano cofounder and CTO of NeoTekSystems, a Greenville, South Carolina technology consulting company. NeoTekSystems offers IT consulting, custom programming, web design and web hosting. We ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Most software today is very much like an Egyptian pyramid with millions of bricks piled on top of each other, with no structural integrity, but just done by brute force and thousands of slaves” - Alan Kay