Delegates and Events—Retrieving Values from Multicast Delegates


Jump to: navigation, search
Visual C# Tutorials
C# Tutorials

Delegates and Events

© 2005 O'Reilly Media, Inc.

Retrieving Values from Multicast Delegates

In most situations, the methods you’ll encapsulate with a multicast delegate will return void. In fact, the most common use of multicast delegates is with events, and you will remember that by convention, all events are implemented by delegates that encapsulate methods that return void (and also take two parameters: the sender and an EventArgs object).

It is possible, however, to create multicast delegates for methods that don’t return void. In the next example, you will create a very simple test class with a delegate that encapsulates any method that takes no parameters but returns an integer:

public class ClassWithDelegate
{
   public delegate int DelegateThatReturnsInt();
   public DelegateThatReturnsInt theDelegate;

To test this, you implement two classes that subscribe to your delegate. The first encapsulates a method that increments a counter and returns that value as an integer:

public class FirstSubscriber
{
   private int myCounter = 0;
 
   public void Subscribe(ClassWithDelegate theClassWithDelegate)
   {
      theClassWithDelegate.theDelegate +=
         new ClassWithDelegate.DelegateThatReturnsInt(DisplayCounter);
   }
 
   public int DisplayCounter()
   {
      return ++myCounter;
   }
}

The second class also maintains a counter, but its delegated method doubles the counter and returns that doubled value:

public class SecondSubscriber
{
   private int myCounter = 0;
   public void Subscribe(ClassWithDelegate theClassWithDelegate)
   {
      theClassWithDelegate.theDelegate +=
         new ClassWithDelegate.DelegateThatReturnsInt(Doubler);
   }
 
   public int Doubler()
   {
      return myCounter += 2;
   }
}

When you fire this delegate, each encapsulated method is called in turn, and each returns a value:

int result = theDelegate();
Console.WriteLine(
   "Delegates fired! Returned result: {0}",
   result);

The problem is that as each method returns its value, it overwrites the value assigned to result. The output looks like this:

Delegates fired! Returned result: 2
Delegates fired! Returned result: 4
Delegates fired! Returned result: 6
Delegates fired! Returned result: 8
Delegates fired! Returned result: 10

The first method, DisplayCounter() (which was called by FirstSubscriber), returned the values 1,2,3,4,5, but these values were overwritten by the values returned by the second method.

Your goal is to display the result of each method invocation in turn. To do so, you must take over the responsibility of invoking the methods encapsulated by your multicast delegate. You do so by obtaining the invocation list from your delegate and explicitly invoking each encapsulated method in turn:

foreach (
   DelegateThatReturnsInt del in
   theDelegate.GetInvocationList() )
{
   int result = del();
   Console.WriteLine(
   "Delegates fired! Returned result: {0}",
   result);
}
Console.WriteLine();

This time, result is assigned the value of each invocation, and that value is displayed before invoking the next method. The output reflects this change:

Delegates fired! Returned result: 1
Delegates fired! Returned result: 2
Delegates fired! Returned result: 2
Delegates fired! Returned result: 4
Delegates fired! Returned result: 3
Delegates fired! Returned result: 6
Delegates fired! Returned result: 4
Delegates fired! Returned result: 8
Delegates fired! Returned result: 5
Delegates fired! Returned result: 10

The first delegated method is counting up (1,2,3,4,5) while the second is doubling (2,4,6,8,10). The complete source is shown in Example 12-5.

Example 12-5. Invoking delegated methods manually

#region Using directives
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
 
#endregion
 
namespace InvokingDelegatedMethodsManually
{
   public class ClassWithDelegate
   {
      // a multicast delegate that encapsulates a method
      // that returns an int
      public delegate int DelegateThatReturnsInt();
      public DelegateThatReturnsInt theDelegate;
      public void Run()
      {
         for ( ; ; )
         {
            // sleep for a half second
            Thread.Sleep( 500 );
            if ( theDelegate != null )
            {
               // explicitly invoke each delegated method
               foreach (
                  DelegateThatReturnsInt del in
                  theDelegate.GetInvocationList() )
               {
                  int result = del();
                  Console.WriteLine(
                     "Delegates fired! Returned result: {0}",
                     result );
               } // end foreach
               Console.WriteLine();
            } // end if
         } // end for ;;
      } // end run
   } // end class
 
   public class FirstSubscriber
   {
      private int myCounter = 0;
      public void Subscribe( ClassWithDelegate theClassWithDelegate )
      {
         theClassWithDelegate.theDelegate +=
            new ClassWithDelegate.DelegateThatReturnsInt( DisplayCounter );
      }
 
      public int DisplayCounter()
      {
         return ++myCounter;
      }
   }
 
   public class SecondSubscriber
   {
      private int myCounter = 0;
 
      public void Subscribe( ClassWithDelegate theClassWithDelegate )
      {
         theClassWithDelegate.theDelegate +=
            new ClassWithDelegate.DelegateThatReturnsInt( Doubler );
      }
 
      public int Doubler()
      {
         return myCounter += 2;
      }
   }
 
   public class Test
   {
      public static void Main()
      {
         ClassWithDelegate theClassWithDelegate =
            new ClassWithDelegate();
         FirstSubscriber fs = new FirstSubscriber();
         fs.Subscribe( theClassWithDelegate );
         SecondSubscriber ss = new SecondSubscriber();
         ss.Subscribe( theClassWithDelegate );
         theClassWithDelegate.Run();
      }
   }
}


Previous_Page_.gif Next_Page_.gif





Personal tools