I just finished an MVC implementation for WinForms as
a tutorial for whomever and as a walkthrough for myself to see if I could find a
nice tidy way to organize my ever increasingly Forms classes. I noticed
something I just can't figure out.
When publishing an event that noone subscribes to I
get a nullreference exception. There are no way (as I can see) to instantiate
the Event in and make sure it's not null so I had to go like this:
... code snipped for brevity ... (ed.)
Is this really the only way to do this? Have I missed
out about something with publish/subscribe? It should be possible to scream
although noone is actually listening..
[mads studentblog]
Yup. That's just the way C#'s event keyword works when
used in it's abbreviated form. An event is really nothing more than a glorified
multi-cast delegate. When defining an event in .NET you're essentially just specifying metadata on your type that says "Hey, I have an event
called 'XXXX' and here are the two methods you can use to subscribe and
unsubscribe.", much like a property is just metadata that points to a pair of get and set
accessors. So when you define an event in C# using the abbreviate form the
compiler is generating add and remove event handler methods for you behind the scenes.
The implementation provided will defer instantiation of the event delegate until
the first subscriber to the event invokes the add_XXXX event subscription method.
Therefore, you must always test your event delegate for null before
invoking it.
Now, something that a lot of people who are new to C# don't
realize is that you can take full control of the event registration methods
yourself by taking the event declaration a step further, like so:
public event EventHandler MyEvent
{
add
{
...
}
remove
{
...
}
}
You can more about the C# event keyword right here
in the SDK.
The prime example of custom event subscription
methods is the Windows Forms Control architecture which makes
extensive use of this technique to reduce the potential overhead associated
with the many of events on control instances that are likely to never even
be subscribed to. The architecture accomplishes this by storing the delegate instances in an
event hashtable on the control instance (see Component::EventHandlerList). The hashtable
is keyed by a static object references representing each event.
Should someone subscribe to a particular event, the delegate is created at that point and cached
for the control instance. This can signifigantly reduce the size of each
control instance by saving the memory of N delegate member variables weighing in at the
cost of a reference variable each. When you consider the fact that the
base Control
class
has 58
events
itself and the cost of a reference variable in the Microsoft .NET runtime
on the x86 platform has a native size of four bytes (32-bit pointer) that's
232 bytes saved per Control (or subclass) instance. This
is a pattern that all component developers should take into consideration
when they hit the optimizing stage of their product. This pattern and
more details about events in .NET are discussed here
in the SDK.