Previous section   Next section

12.2 Multicasting

At times it is desirable to multicast, or call two implementing methods through a single delegate. You accomplish multicasting by encapsulating the various methods in delegates. Then you combine the delegates using the Delegate.Combine( ) shared method. The Combine( ) method takes an array of delegates as a parameter and returns a new delegate that represents the combination of all the delegates in the array.

To see how this works, create a simplistic class that declares a delegate:

Public Class MyClassWithDelegate
    ' the delegate declaration
    Public Delegate Sub StringDelegate(ByVal s As String)
End Class

Then create a class (MyImplementingClass) that implements a number of methods that match the StringDelegate:

Public Class MyImplementingClass

    Public Shared Sub WriteString(ByVal s As String)
        Console.WriteLine("Writing string {0}", s)
    End Sub

    Public Shared Sub LogString(ByVal s As String)
        Console.WriteLine("Logging string {0}", s)
    End Sub

    Public Shared Sub TransmitString(ByVal s As String)
        Console.WriteLine("Transmitting string {0}", s)
    End Sub
End Class

Within the Run( ) method of your Tester class, you'll instantiate three StringDelegate objects (Writer, Logger, Transmitter):

Dim Writer, Logger, Transmitter As MyClassWithDelegate.StringDelegate

You instantiate these delegates by passing in the address of the methods you wish to encapsulate:

Writer = New MyClassWithDelegate.StringDelegate( _
     AddressOf MyImplementingClass.WriteString)
Logger = New MyClassWithDelegate.StringDelegate( _
     AddressOf MyImplementingClass.LogString)
Transmitter = New MyClassWithDelegate.StringDelegate( _
      AddressOf MyImplementingClass.TransmitString)

You next instantiate a multicast delegate (myMulticastDelegate) that you'll use to combine the three other delegates:

Dim myMulticastDelegate As MyClassWithDelegate.StringDelegate

Next you create an array of the first two delegates:

Dim arr( ) As MyClassWithDelegate.StringDelegate = {Writer, Logger}

and use that array to instantiate the multicast delegate:

myMulticastDelegate = _
  DirectCast(System.Delegate.Combine(arr), _
    MyClassWithDelegate.StringDelegate)

DirectCast is used to cast the result of calling Combine( ) to the specialized type MyClassWithDelegate.StringDelegate, because Combine returns an object of the more general type Delegate.

Then you can add the third delegate to the collection by calling the overloaded Combine( ) method, this time passing in the existing multicast delegate and the new delegate to add:

myMulticastDelegate = _
   DirectCast(System.Delegate.Combine(myMulticastDelegate, Transmitter), _
   MyClassWithDelegate.StringDelegate)

You can remove just the Logger delegate by calling the static method Remove( ), passing in the multicast delegate and the delegate you wish to remove. The return value is a Delegate, which you cast to a StringDelegate and assign back to the multicast delegate:

myMulticastDelegate = _
   DirectCast(System.Delegate.Remove(myMulticastDelegate, Logger), _
                      MyClassWithDelegate.StringDelegate)

Example 12-3 shows the complete code for this listing.

Example 12-3. Multicasting
Option Strict On
Imports System

Namespace Multicasting

    Public Class MyClassWithDelegate
        ' the delegate declaration
        Public Delegate Sub StringDelegate(ByVal s As String)
    End Class

    Public Class MyImplementingClass

        Public Shared Sub WriteString(ByVal s As String)
            Console.WriteLine("Writing string {0}", s)
        End Sub

        Public Shared Sub LogString(ByVal s As String)
            Console.WriteLine("Logging string {0}", s)
        End Sub

        Public Shared Sub TransmitString(ByVal s As String)
            Console.WriteLine("Transmitting string {0}", s)
        End Sub
    End Class

    Class Tester

        Public Sub Run( )
            ' define three StringDelegate objects
            Dim Writer, Logger, Transmitter As _
               MyClassWithDelegate.StringDelegate

            ' define another StringDelegate
            ' to act as the multicast delegate
            Dim myMulticastDelegate As MyClassWithDelegate.StringDelegate

            ' Instantiate the first three delegates, 
            ' passing in methods to encapsulate
            Writer = New MyClassWithDelegate.StringDelegate( _
                 AddressOf MyImplementingClass.WriteString)
            Logger = New MyClassWithDelegate.StringDelegate( _
                 AddressOf MyImplementingClass.LogString)
            Transmitter = New MyClassWithDelegate.StringDelegate( _
                  AddressOf MyImplementingClass.TransmitString)

            ' Define array of StringDelegates
            Dim arr( ) As MyClassWithDelegate.StringDelegate = _
               {Writer, Logger}

            ' Invoke the Writer delegate method
            ' vbCrLf is the VB equivalent of Environment.NewLine 
            Writer("String passed to Writer" & vbCrLf)

            ' Invoke the Logger delegate method 
            Logger("String passed to Logger" & vbCrLf)

            ' Invoke the Transmitter delegate method
            Transmitter("String passed to Transmitter" & vbCrLf)

            ' Tell the user you are about to combine
            ' two delegates into the multicast delegate
            Console.WriteLine(vbCrLf & "myMulticastDelegate = " + _
               "Writer and Logger")

            ' combine the two delegates, the result is
            ' assigned to myMulticast Delegate
            myMulticastDelegate = _
              DirectCast(System.Delegate.Combine(arr), _
                MyClassWithDelegate.StringDelegate)

            ' Call the delegated methods, two methods
            ' will be invoked
            myMulticastDelegate("First string passed to Collector")

            ' Tell the user you are about to add
            ' a third delegate to the multicast
            Console.WriteLine(vbCrLf & _
               "myMulticastDelegate Adds Transmitter")

            ' add the third delegate
            myMulticastDelegate = _
              DirectCast(System.Delegate.Combine(myMulticastDelegate, _
                 Transmitter), _
                 MyClassWithDelegate.StringDelegate)

            ' invoke the three delegated methods
            myMulticastDelegate("Second string passed to Collector")

            ' tell the user you are about to remove
            ' the logger delegate
            Console.WriteLine(vbCrLf & "myMulticastDelegate -= Logger")

            ' remove the logger delegate
            myMulticastDelegate = _
               DirectCast(System.Delegate.Remove(myMulticastDelegate, _
                  Logger),  MyClassWithDelegate.StringDelegate)

            ' invoke the two remaining 
            ' delegated methods
            myMulticastDelegate("Third string passed to Collector")
        End Sub

        Public Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub
    End Class

End Namespace ' Multicasting

Output:
Writing string String passed to Writer

Logging string String passed to Logger

Transmitting string String passed to Transmitter


myMulticastDelegate = Writer and Logger
Writing string First string passed to Collector
Logging string First string passed to Collector

myMulticastDelegate Adds Transmitter
Writing string Second string passed to Collector
Logging string Second string passed to Collector
Transmitting string Second string passed to Collector

myMulticastDelegate -= Logger
Writing string Third string passed to Collector
Transmitting string Third string passed to Collector

  Previous section   Next section
Top