Click to Rate and Give Feedback
Related Articles
Here the author introduces SQL Server Data Services, which exposes its functionality over standard Web service interfaces.

By David Robinson (July 2008)
Here the author answers questions regarding the Entity Framework and provides an understanding of how and why it was developed.

By Elisa Flasko (July 2008)
Here we present techniques for programmatic and declarative data binding and display with Windows Presentation Foundation.

By Josh Smith (July 2008)
Systems that handle failure without losing data are elusive. Learn how to achieve systems that are both scalable and robust.

By Udi Dahan (July 2008)
More ...
Articles by this Author
In this month’s installment of .NET Matters, columnist Stephen Toub answers reader questions concerning asynchronous I/O .

By Stephen Toub (July 2008)
This month Stephen Toub discusses asynchronous stream processing.

By Stephen Toub (March 2008)
This month Stephen Toub explains how to make the most of dual processors when running encryption and compression tasks.

By Stephen Toub (February 2008)
The author creates a managed wrapper to use the new IFileOperations interface in Windows Vista from managed code.

By Stephen Toub (December 2007)
Find out how to use finalizers as a way to warn developers who use your custom types when they are garbage collected without having been disposed of correctly.

By Stephen Toub (November 2007)
This month Stephen Toub discusses deadlocks that can occur when synchronizing threads.

By Stephen Toub (October 2007)
Stephen Toub and Shawn Farkas discuss creating an adapter that takes the functionality of RNGCryptoServiceProvider and adapts it to the interface of Random.

By Stephen Toub and Shawn Farkas (September 2007)
Stephen Toub gets nostalgic as he prepares to leave MSDN Magazine.

By Stephen Toub (August 2007)
More ...
Popular Articles
Systems that handle failure without losing data are elusive. Learn how to achieve systems that are both scalable and robust.

By Udi Dahan (July 2008)
Jay Flowers demonstrates how to set up and use a Continuous Integration server using both discrete tools and the more comprehensive CI Factory solution.

By Jay Flowers (March 2008)
Mike Volodarsky demonstrates the IIS 7.0 extensibility model by extending the Response Modification into a configurable Web server module and a custom management page for IIS Manager.

By Mike Volodarsky (Launch 2008)
In this article we introduce you to BizTalk Services, new technology that offers the Enterprise Service Bus features of BizTalk Server as a hosted service.

By Jon Flanders and Aaron Skonnard (June 2008)
More ...
Read the Blog
In the November issue of MSDN Magazine, Jeffrey Richter demonstrates some recent additions to the C# programming language that make working with the APM significantly easier. In the June ...
Read more!
The July 2008 issue of MSDN Magazine is now available online. Here's what's in the issue: Data Services: Develop ...
Read more!
The June 2008 issue features the first installment of a new MSDN Magazine column on software design fundamentals. We’ll discuss design patterns and principles in a manner that isn't bound to a specific tool or lifecycle methodology. In this issue, Jeremy Miller starts the Patterns in Practice column ...
Read more!
In the April 2008 issue of MSDN Magazine, Kenny Kerr introduced the Windows Imaging Component (WIC), showing you how you can use it to encode and decode different image ...
Read more!
A combination of the retained-mode graphics system and notification mechanisms such as dependency properties unleash the flexibility and power of Windows Presentation Foundation (WPF, allowing these objects to be targets of data bindings and animations. In the June 2008 issue of MSDN Magazine, Charles ...
Read more!
One problem with GUI programming in C++ is that most libraries are too low level, putting much of the burden on the programmer. In the June 2008 issue of MSDN Magazine, John Torjo introduces you eGUI++, a C++ library that gives you a ...
Read more!
More ...
.NET Matters
Event Accessors
Stephen Toub


Q C# makes it very easy to create events on classes, simply by adding the keyword "event" to a delegate member variable declaration. However, it also allows a property-like syntax where add and remove accessors for the event can be implemented explicitly. Why would I ever want to do that? Wouldn't I always just be recreating the same code the C# compiler generates for me?
Q C# makes it very easy to create events on classes, simply by adding the keyword "event" to a delegate member variable declaration. However, it also allows a property-like syntax where add and remove accessors for the event can be implemented explicitly. Why would I ever want to do that? Wouldn't I always just be recreating the same code the C# compiler generates for me?

A There are several reasons you might want or need to implement your own add and remove accessors for an event in C#. I'll take a look at several of these (this isn't an exhaustive list) and show how custom accessors can enable new functionality or even improve performance.
A There are several reasons you might want or need to implement your own add and remove accessors for an event in C#. I'll take a look at several of these (this isn't an exhaustive list) and show how custom accessors can enable new functionality or even improve performance.
To begin, consider a simple class, MyClass, with a typical instance event, MyEvent:
class MyClass
{
    public event EventHandler MyEvent;
    ...
}
When the C# compiler generates code for MyClass, the output Microsoft® Intermediate Language (MSIL) is identical in behavior to what would have been produced using code like that in Figure 1.
With the simple event syntax, when you reference MyEvent in your code in order to invoke it, the C# compiler translates that into a call to the underlying delegate, such that a call like the following
MyEvent(this, EventArgs.Empty);
actually compiles down to code like:
_myEvent(this, EventArgs.Empty);
Using the explicit implementation, where you write your own custom add and remove accessors, the compiler doesn't know about the underlying data store for the event, so you can no longer invoke the event using the name of the event itself, but rather you must reference the delegate directly.
This hints at one of the primary reasons for writing your own add and remove accessors: to provide your own underlying data store. One reason you might want to do this is if you have lots of exposed events on your class, but in such a way that only a few are typically in use on an instance at any point in time. In such a scenario, there can be significant memory overhead associated with maintaining a delegate field for each event. Take the Windows® Forms Control class as an example.
In the Microsoft .NET Framework 2.0, Control exposes 69 public events. If each of these events had an underlying delegate field, on a 32-bit system these events would add an overhead of 276 bytes per instance. Instead, Control (or, more specifically, its base class System.ComponentModel.Component) maintains a list of key/value pairs, where the value is a delegate. Every event on Control then has custom add and remove accessors that store the registered delegates for all events into this list, an instance of the System.ComponentModel.EventHandlersList class. Assuming that only a few events on a particular Control are handled, the performance impact of having to search through the EventHandlersList for a particular delegate is minimal, and the memory overhead is limited to what's necessary for the EventHandlersList implementation. You can implement this same pattern in your own classes, as shown in Figure 2.
I've followed the convention used in Windows Forms, which is to have one static object for each event to use as the key into each EventHandlerList. Since this is a static field, there's only one for the whole AppDomain, rather than one for each instance. You could opt to use a string for the key, but then you run the risk of typos that won't be caught until the relevant lookups fail at runtime; the static object approach moves most of these kinds of failures to compile time.
A related use for explicit event implementation, even if you want to use a single delegate as the backing store for the event, is to augment the delegate with attributes. The most common example of why this may be important is serialization. The .NET serialization mechanism, by default, serializes out all fields of a serializable class, regardless of their accessibility (this is in contrast to XML serialization, where by default only public fields and public properties are serialized). All fields of a serializable class must either themselves be serializable or must be exempted from the serialization process using the NonSerializable attribute (alternatively, the class can implement the ISerializable interface to completely control what data is serialized and how), since they will be traversed by a formatter saving out the object graph.
The trouble with events when it comes to .NET serialization is that they're backed by a private delegate field, and delegates are serializable. When you create a delegate for an instance method, the delegate maintains a reference to the instance on which to call that method, so when you serialize an object that contains an event, the formatter, while walking the object graph, will continue on down through the delegate attempting to serialize any instances registered with that delegate. If you're not aware of this and don't plan accordingly, you could experience some unwelcome side effects. If it's not the behavior you want, a solution is to mark the backing store for the event with the NonSerializableAttribute, as shown in Figure 3. This will cause the formatter to skip that field when serializing out the object graph.
Another use for explicit event implementation is to provide a custom synchronization mechanism (or to remove one). You'll notice in Figure 1 that both the add and remove accessors are adorned with a MethodImplAttribute that specifies that the accessors should be synchronized. For instance events, this attribute is equivalent to wrapping the contents of each accessor with a lock on the current instance:
add { lock(this) _myEvent += value; }
remove { lock(this) _myEvent -= value; }
If you're writing a class that will not be used from multiple threads, there's no point in the overhead of taking this lock, so you could provide a custom implementation that lacks the MethodImplAttribute. However, the overhead of taking such a lock in typical event-usage scenarios is negligible, so it's rare that this would justify a custom implementation. More importantly, however, it's considered poor form to use lock(this), as in effect you're exposing what should be an implementation detail (the lock) to all consumers of your class (they, too, can lock on your instance). If locking is necessary, it's considered a better practice to lock on a private object. And if you're not synchronizing around the "this" reference, then the default event implementation that does synchronize around that reference will most likely be incorrect, since it won't be synchronized in the same manner as the rest of your class.
Another situation exists in which you may need to explicitly implement an event. Consider two interfaces that both have an event with the same name:
interface I1
{
    event EventHandler MyEvent;
}

interface I2
{
    event EventHandler MyEvent;
}
If I want a class to implement both of these interfaces, I can do so as follows:
class MyClass : I1, I2
{
    public event EventHandler MyEvent;
}
Here, MyClass.MyEvent implements both I1.MyEvent and I2.MyEvent. But what if I want MyClass to provide separate implementations for I1.MyEvent and I2.MyEvent? The only way to do so is to use an explicit interface implementation for at least one of the interfaces (though I could do so for both):
class MyClass : I1, I2
{
    public event EventHandler MyEvent;

    private EventHandler _i2MyEvent;
    event EventHandler I2.MyEvent
    {
        add { _i2MyEvent += value; }
        remove { _i2MyEvent -= value; }
    }
}
A fourth reason you might implement custom add or remove accessors is to execute custom logic any time a delegate is registered or unregistered from the event. In what scenarios would that be useful? Several.
Consider the Microsoft.Win32.SystemEvents class. This class exposes over a dozen public static events that are raised in response to various happenings on the system: DisplaySettingsChanged, InstalledFontsChanged, UserPreferenceChanging, and so forth. An application is informed of most of these system notifications through Windows messages. For SystemEvents to raise .NET events for the notifications, it needs a window to listen for them and a thread running a message loop to respond to them. There's overhead involved in such functionality, so SystemEvents only wants to initialize (creating the broadcast window, running the message loop, and so forth) if a delegate is registered with one of the events. And the perfect place to kick off the logic to ensure the class has been initialized is in the add accessor for the delegate, as shown in Figure 4.
Another kind of custom logic you might want executed when a delegate is registered is permission demands. Take the System.Diagnostics.EventLog class as an example. Many of the operations on EventLog are gated by the EventLogPermission, which allows for permission states as specified through an EventLogPermissionAccess enumeration, with members like Administer, Write, and None. The EventLog class exposes a public EntryWritten event that is raised whenever an entry is written to the log, but that act of responding to new entries in an event log requires the Administer permission. Where should that permission be demanded? Code that doesn't have the permission shouldn't be allowed to register a delegate with the event, so a demand can be done in the add accessor, as shown in Figure 5.
The System.Console class makes use of custom logic for both custom initialization and permission demands. Console exposes the static CancelKeyPress event, which is raised when the Ctrl+C or Ctrl+Break key combinations are used in the console. Typically these will terminate the process, but if a ConsoleCancelEventArgs delegate is registered with the event, that delegate can override the termination through the ConsoleCancelEventArgs.Cancel property. In order to perform this interception, Console must register a handler to hook the signals using SetConsoleCtrlHandler from Kernel32.dll, and an appropriate place to do this is in the add accessor for the event (the remove accessor contains the corresponding logic to unregister the handler). Additionally, CancelKeyPress requires UIPermissionWindow.SafeTopLevelWindows permission, and thus it's demanded in both accessors for the event.
A much more obscure use of custom logic in an add accessor (for the very advanced developers out there) is useful for events to be raised within constrained execution regions, or CERs. (For a detailed look at CERs, see my article in the October 2005 issue of MSDN®Magazine. The basic idea here is that asynchronous exceptions resulting from situations such as out-of-memory can destabilize an application by interrupting normal code flow in a way that prevents standard backout code from executing correctly. In order to help prevent these types of conditions from occurring, code can be JIT-compiled and prepared ahead of time such that these sorts of conditions are hopefully moved to either before or after the code runs.
Now consider an event that is to be raised from within a CER, where you want to avoid all of these dangerous conditions. You want to prepare ahead of time all of the code to be executed in the CER, but if you're raising an event to which any delegate can be registered, unprepared code could in fact run within the CER. This is exactly the situation that several events on the AppDomain class run into. For example, AppDomain.ProcessExit is raised from within a CER, so all delegates registered with it should be prepared ahead of time. How can this be accomplished? By adding code to the event's add accessor that prepares the supplied delegate before it's registered with the event, as shown in Figure 6.
This is just a subset of reasons why you might want to provide your own add and remove accessors for an event. Most of the time, the stock accessors generated by the compiler are fine. But there may be times when you need more control, making this a very handy feature to have in your back pocket.

Send your questions and comments for Stephen to netqa@microsoft.com.


Stephen Toub is the Technical Editor for MSDN Magazine.

Page view tracker