The following is the standard way to define a delegate:
public delegate void PhoneRangHandler ( object sender, EventArgs e ); public event PhoneRangHandler PhoneRang;
Reference types.
To decouple the method(s) called from the calling code. It allows the designer of an object to define the delegate, and the user of the object to define which method will be called when the delegate is invoked.
You instantiate a delegate like this:
OnPhoneRings myDelegate = new OnPhoneRings(myMethod);
Here is how to call a delegated method:
OnPhoneRings(object this, new EventArgs( ));
The ability for more than one method to be called through a single delegate.
Limits the use of the delegate in the following ways:
You can only add a method using +=
.
You can only remove a method using -=
.
The delegate can only be invoked by the class that defines it.
Define the delegate to take, as its second parameter, an
object of a type derived from EventArgs
. Pass the information
through properties of that object.
None.
Rather than creating a method that matches the delegate’s signature and then assigning the name of that method to the delegate, you can directly assign an unnamed delegate method by providing the implementation in line with the assignment.
Write a countdown alarm program that uses delegates to notify anyone who is interested that the designated amount of time has passed:
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace Exercise1 { // a class to hold the message to display public class CountDownClockEventArgs : EventArgs { public readonly string message; public CountDownClockEventArgs( string message ) { this.message = message; } } // The subject (publisher). The class to which other // classes will subscribe. Provides the delegate TimeExpired // that fires when the requested amount of time has passed public class CountDownClock { private DateTime startingTime; private DateTime targetTime; private string message; // tell me the message to display, and how much time //(hours, minutes seconds) to wait public CountDownClock( string message, int hours, int mins, int seconds ) { this.message = message; startingTime = DateTime.Now; TimeSpan duration = new TimeSpan( hours, mins, seconds ); targetTime = startingTime + duration; } // the delegate public delegate void TimesUpEventHandler ( object countDownClock, CountDownClockEventArgs alarmInformation ); // an instance of the delegate public TimesUpEventHandler TimeExpired; // Check 10 times a second to see if the time has elapsed // if so, if anyone is listening, send then message public void Run( ) { for ( ; ; ) { // sleep 1/10 of a second Thread.Sleep( 100 ); // milliseconds // get the current time System.DateTime rightNow = System.DateTime.Now; if ( rightNow >= this.targetTime ) { if ( TimeExpired != null ) { // Create the CountDownClockEventArgs to hold the message CountDownClockEventArgs e = new CountDownClockEventArgs( this.message ); // fire the event TimeExpired( this, e ); // stop the timer break; } // end if registered delegates } // end if time has passed } // end forever loop } // end run } // end class // an observer. public class CountDownTimerDisplay { CountDownClock.TimesUpEventHandler myHandler; public CountDownTimerDisplay(CountDownClock cdc) { myHandler = new CountDownClock.TimesUpEventHandler( TimeExpired ); // register the event handler and start the timer cdc.TimeExpired += myHandler; } // Alert the user that the time has expired public void TimeExpired( object theClock, CountDownClockEventArgs e ) { Console.WriteLine( e.message ); } } // an observer. public class CountDownTimerLog { CountDownClock.TimesUpEventHandler myHandler; public CountDownTimerLog( CountDownClock cdc ) { myHandler = new CountDownClock.TimesUpEventHandler( TimeExpired ); // register the event handler and start the timer cdc.TimeExpired += myHandler; } // Alert the user that the time has expired public void TimeExpired( object theClock, CountDownClockEventArgs e ) { Console.WriteLine( "logging " + e.message ); } } public class Test { public static void Main( ) { Console.Write( "Message: " ); string message = Console.ReadLine( ); // NB: You would of course create a more sophisticated interface to // let the user set the correct amount of time. For now, we'll just // ask for how many seconds to wait Console.Write( "How many seconds?: " ); int seconds = Convert.ToInt32( Console.ReadLine( ) ); CountDownClock cdc = new CountDownClock( message, 0, 0, seconds ); CountDownTimerDisplay display = new CountDownTimerDisplay( cdc ); CountDownTimerLog logger = new CountDownTimerLog (cdc); cdc.Run( ); } } }
Break the program you write in Exercise 17-1 by assigning a new handler to the delegate (deleting the old!).
The only change is in the registration of the handler,
using =
rather than +=
:
public class CountDownTimerLog
{
CountDownClock.TimesUpEventHandler myHandler;
public CountDownTimerLog( CountDownClock cdc )
{
myHandler = new CountDownClock.TimesUpEventHandler( TimeExpired );
// register the event handler and start the timercdc.TimeExpired = myHandler
;
}
// Alert the user that the time has expired
public void TimeExpired( object theClock, CountDownClockEventArgs e )
{
Console.WriteLine( "logging " + e.message );
}
}
Fix the program you wrote in Exercise 17-1 by using the
event
keyword and test
against changes you added in Exercise 17-2.
The only change is in the declaration of the instance of
the delegate, adding the keyword event, which will make Exercise
17-2 fail at compile time. Repairing it from =
to +=
will let it run as an event.
// the delegate
public delegate void TimesUpEventHandler
(
object countDownClock,
CountDownClockEventArgs alarmInformation
);
// an instance of the delegate
publicevent
TimesUpEventHandler TimeExpired;