Working with Delegates in C# - ' Delegates and Events ' (
Page 5 of 6 )
Delegates and Events
A full discussion of delegates is incomplete without covering the close relationship they have with C# events. An event is a type member that enables a type to send notifications about things that happen in that type. Typical .NET events include things like the mouse actions and keyboard key presses that your application captures.
Events are better than delegates for implementing callbacks, because they provide more protection. In fact, the underlying implementation of an event is actually a delegate. Event restrictions include protection from accidental assignment and prevention of outside callers invoking the event.
ADVERTISEMENT
With delegates, an assignment of a delegate (=), rather than an add (+=) will wipe out all delegates previously added to its invocation list, which is something you generally don't want happening to events that your code raises.
The other restriction, preventing outside callers from raising your event, gives you full control over the behavior of your type. It is necessary for a type to control the logic that raises its own events. To have something outside your type reaching in and firing your events could wreak havoc with your application. If you want code outside your type to be able to fire your event, you should provide a convenience method that will still give you more control over how the event is raised. Listing 4 shows how to use events and shows their restrictions as well as demonstrating the hazards you could face with delegates.
Listing 4: EventListener.cs
using System;
class EventListener
{
static void Main()
{
EventPublisher publisher = new EventPublisher();
EventListener listener = new EventListener();
publisher.InterestingEvent += new EventHandler(listener.HandlerOne);
publisher.InterestingEvent += new EventHandler(listener.HandlerTwo);
publisher.InterestingDelegate += new EventHandler(listener.HandlerOne);
// assignment accidentally wiped out delegate for listener.HandlerOne
publisher.InterestingDelegate = new EventHandler(listener.HandlerTwo);
// illegal
// publisher.InterestingEvent = null;
// can't invoke event outside of its containing class
// publisher.InterestingEvent(listener, EventArgs.Empty);
Console.WriteLine("\nInvoking Event:\n");
publisher.FireEvent();
Console.WriteLine("\nInvoking Delegate:\n");
publisher.InterestingDelegate(listener, EventArgs.Empty);
Console.ReadLine();
}
public void HandlerOne(object sender, EventArgs e)
{
Console.WriteLine("HandlerOne Called.");
}
public void HandlerTwo(object sender, EventArgs e)
{
Console.WriteLine("HandlerTwo Called.");
}
}
class EventPublisher
{
// declare event
public event EventHandler InterestingEvent;
// declare public delegate
public EventHandler InterestingDelegate;
public void FireEvent()
{
InterestingEvent(this, EventArgs.Empty);
}
}
The EventPublisher class in Listing 4 has a declaration for both a delegate and an event. Since the event can be raised only from within its containing type, the FireEvent method is declared for the purpose of raising the event. (Normally, the event would be raised for some type of state change within the type, but this example is simplified to demonstrate the mechanics.)
The EventListener class adds delegates to both the InterestingEvent event and InterestingDelegate delegate of the publisher instance. Using the assignment operator on InterestingDelegate demonstrates the type of accidents that can happen with delegates. Assignment of a null value to InterestingEvent and a direct invocation of InterestingEvent are commented out in the listing. You can uncomment those lines separately, to verify the type of compiler error you'll see when trying each, proving the inherent safety of events over delegates in this situation. While InterestingDelegate is invoked directly, InterestingEvent is invoked indirectly, showing one way to cause an event invocation from outside a type. A similar scenario is possible in .NET Windows Forms where you can call PerformClick on Button and MenuItem types to simulate a mouse button click.