Team LiB   Previous Section   Next Section

19.2 Multicasting

At times it is desirable to multicast: to call two implementing methods through a single delegate. This becomes particularly important when handling events (discussed later in this chapter).

With multicasting, you create a single delegate that calls multiple encapsulated methods. For example, when a button is pressed, you might want to take more than one action. You could implement this by giving the button a collection of delegates, but it is cleaner and easier to create a single multicast delegate.

Two delegates can be combined with the addition operator (+). The result is a new multicast delegate that invokes both of the original implementing methods. For example, assuming Writer and Logger are delegates, the following line will combine them and produce a new multicast delegate named myMulticastDelegate:

myMulticastDelegate = Writer + Logger;

You can add delegates to a multicast delegate using the plus-equals (+=) operator. This operator adds the delegate on the right side of the operator to the multicast delegate on the left. For example, assuming Transmitter and myMulticastDelegate are delegates, the following line adds Transmitter to myMulticastDelegate:

myMulticastDelegate += Transmitter;

To see how multicast delegates are created and used, let's walk through a complete example. Example 19-3 is followed by a complete analysis.

Example 19-3. Multicast delegates
using System;

namespace DelegatesAndEvents
{
    public class MyClassWithDelegate
    {
        // The delegate declaration.
        public delegate void StringDelegate(string s);

    }

    public class MyImplementingClass
    {
        public static void WriteString(string s)
        {
            Console.WriteLine("Writing string {0}", s);
        }

        public static void LogString(string s)
        {
            Console.WriteLine("Logging string {0}", s);
        }

        public static void TransmitString(string s)
        {
            Console.WriteLine("Transmitting string {0}", s);
        }

    }

   class Tester
   {
      public void Run()
      {
          // Define three StringDelegate objects.
          MyClassWithDelegate.StringDelegate 
              Writer, Logger, Transmitter;

          // Define another StringDelegate
          // to act as the multicast delegate.
          MyClassWithDelegate.StringDelegate 
              myMulticastDelegate;

          // Instantiate the first three delegates, 
          // passing in methods to encapsulate.
          Writer = new MyClassWithDelegate.StringDelegate(
              MyImplementingClass.WriteString);
          Logger = new MyClassWithDelegate.StringDelegate(
              MyImplementingClass.LogString);
          Transmitter = 
              new MyClassWithDelegate.StringDelegate(
              MyImplementingClass.TransmitString);

          // Invoke the Writer delegate method.
          Writer("String passed to Writer\n");

          // Invoke the Logger delegate method. 
          Logger("String passed to Logger\n");

          // Invoke the Transmitter delegate method.
          Transmitter("String passed to Transmitter\n");
            
          // Tell the user you are about to combine
          // two delegates into the multicast delegate.
          Console.WriteLine(
              "myMulticastDelegate = Writer + Logger");

          // Combine the two delegates;  assign the result 
          // to myMulticastDelegate
          myMulticastDelegate = Writer + Logger;

          // 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(
              "\nmyMulticastDelegate += Transmitter");

          // Add the third delegate.
          myMulticastDelegate += Transmitter;

          // Invoke the three delegated methods.
          myMulticastDelegate(
              "Second string passed to Collector");

          // Tell the user you are about to remove
          // the Logger delegate.
          Console.WriteLine(
              "\nmyMulticastDelegate -= Logger");

          // Remove the Logger delegate.
          myMulticastDelegate -= Logger;

          // Invoke the two remaining delegated methods.
          
          myMulticastDelegate(
              "Third string passed to Collector");
      }

      [STAThread]
      static void Main()
      {
         Tester t = new Tester();
         t.Run();
      }
   }
}
Output:
Writing string String passed to Writer

Logging string String passed to Logger

Transmitting string String passed to Transmitter

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

myMulticastDelegate += 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

In Example 19-3, you create a class called MyClassWithDelegate, which defines a delegate that takes a string as a parameter and returns void:

public delegate void StringDelegate(string s);

You then define a class called MyImplementingClass that has three methods, all of which return void and take a string as a parameter: WriteString(), LogString(), and TransmitString(). The first writes the string to standard output, the second simulates writing to a log file, and the third simulates transmitting the string across the Internet. You instantiate the delegates to invoke the appropriate methods:

Writer("String passed to Writer\n");
Logger("String passed to Logger\n");
Transmitter("String passed to Transmitter\n");

To see how to combine delegates, create another Delegate instance:

MyClassWithDelegate.StringDelegate myMulticastDelegate;

and assign to it the result of "adding" two existing delegates:

myMulticastDelegate = Writer + Logger;

Add to this delegate an additional delegate using the += operator:

myMulticastDelegate += Transmitter;

Finally, selectively remove delegates using the -= operator:

DelegateCollector -= Logger;

In the Run() method, the delegates are declared:

MyClassWithDelegate.StringDelegate 
    Writer, Logger, Transmitter;

MyClassWithDelegate.StringDelegate 
    myMulticastDelegate;

The three instance delegates are defined:

Writer = new MyClassWithDelegate.StringDelegate(
    MyImplementingClass.WriteString);
Logger = new MyClassWithDelegate.StringDelegate(
    MyImplementingClass.LogString);
Transmitter = 
    new MyClassWithDelegate.StringDelegate(
    MyImplementingClass.TransmitString);

and invoked:

Writer("String passed to Writer\n");
Logger("String passed to Logger\n");
Transmitter("String passed to Transmitter\n");

The fourth delegate, myMulticastDelegate, is then assigned the combination of the first two and is invoked, causing both delegated methods to be called:

myMulticastDelegate = Writer + Logger;
myMulticastDelegate(
     "First string passed to Collector");

The third delegate is added, and when myMulticastDelegate is invoked, all three delegated methods are called:

myMulticastDelegate += Transmitter;
myMulticastDelegate(
    "Second string passed to Collector");

Finally, Logger is removed, and when myMulticastDelegate is invoked, only the two remaining methods are called:

myMulticastDelegate -= Logger;
myMulticastDelegate(
    "Third string passed to Collector");

The power of multicast delegates is best understood in terms of events, discussed in the next section. When an event such as a button press occurs, an associated multicast delegate can invoke a series of event handler methods that will respond to the event.

    Team LiB   Previous Section   Next Section