Common Type System—Events
Events
CLR types may contain events. Much like properties, events are more of a convention and pattern than a
feature of the CTS itself. As such, they too are marked with the specialname token. Events enable
clients to subscribe to get notifications about interesting occurrences having to do with a type. For example,
Windows Forms uses events quite extensively to enable programmers to respond to various UI events,
such as a button click, the window closing, the user typing a key in a textbox, and so on. They can, of
course, also be used for communication associated with your object models.
C# makes it simple to express events. The event keyword is used to declare a member on a class, for
example:
using System; class Foo : IDisposable { public event EventHandler OnInitialized; public event EventHandler OnDisposed; public void Init() { // Initialize our state... EventHandler onInit = OnInitialized; if (onInit != null) onInit(this, new EventArgs()); } public void Dispose() { // Release our state... EventHandler onDisp = OnDisposed; if (onDisp != null) onDisp(this, new EventArgs()); } }
The type Foo exposes two events, OnInitialized and OnDisposed, to which consumers may subscribe.
Each is of type EventHandler, which is a delegate type in the System namespace. Delegates are
a crucial part of the CTS, discussed later in this chapter. In this example, we accepted the default implementation
for subscription and removal of events, although C# also offers a more powerful syntax to
write your own implementation. We signal that the events have occurred by calling the delegates represented
by our events. If nobody has subscribed, the delegate will be null; thus, we check before trying
to make the call (to avoid a NullReferenceException).
Clients may then subscribe to these events:
using (Foo f = new Foo()) { f.OnInitialized += delegate { Console.WriteLine("init"); }; f.OnDisposed += delegate { Console.WriteLine("disposed"); }; // ... f.Init(); // ... }
The client here subscribes to the events using C#’s += syntax. Notice that the code used to respond to an
event is represented by passing an anonymous delegate. This exposes a form of user extensibility in
your APIs.
The representation of events in the IL is not quite as straightforward as C# makes it look. It gets compiled
into an add_OnXxx and remove_OnXxx method, each of which accepts an EventHandler instance. The
list of event subscriptions is stored inside a Delegate, which offers methods like Combine and Remove
to participate with events.
|

