Safely firing an event, Part 2

Published 17 June 04 02:27 PM

A while back I wrote about Safely firing an event.

 

I come to you now with another solution to the problem, which I like quite a bit more.

 

In Properties with events: another attempt, we tried initializing an event with an empty anonymous method.  It works, but there’s always a risk that one of your constructors won’t do the right thing.

 

It turns out that you can use a field initializer on an event.  I don’t know why I didn’t try this yesterday, its seems obvious now!

 

            public event System.EventHandler MyEvent = delegate { };

 

                  c.MyEvent(this, EventArgs.Empty); // no null check required!

Voila!  The event will never be null.

 

There may be a small perf hit, but until my perf analysis tells me that this specific instance is a perf problem, I’m fine as-is.

 

If your class wants to check if there are any listeners, it can no longer do:

 

                  if (c.MyEvent == null)

                  {

                        // no one listens to me.

                  }

 

Instead you’d have to do:

 

                  // 1 because it always contains the empty delegate

                  if (c.MyEvent.GetInvocationList().Length == 1)

                  {

                        // no one listens to me.

                  }

 

If I am ever inclined to write such code, I will first think about changing my design so the problem goes away, and second do some Extract Method Refactorings to hide the nasty bits.

Comments

# C# Frequently Asked Questions said on June 17, 2004 5:31 PM:
# Eric Newton said on June 17, 2004 10:13 PM:
why would i ever use method 2 over testing for null?

method 1 does one simple test... whereas method 2 has to call a virtual method to retrieve an array which has to provide the length of invokers and what not...

seriously man, why would you EVER favor method2 over simply checking for null???
# Thomas Eyde said on June 18, 2004 12:05 AM:
This must be the one place the C# makers stepped without Anders Hejlsberg's knowledge. Either that or he's getting old.

Why on Earth do I have to check a language construct? Even worse, why do I have to check a language construct I should have complete control over?

The event is created in my class. How come my clients have all the benefits with simple usages, why I have to do all these null checks and race condition hacks?

The event construct in C# is not very OO. I mean, you fire an event because you don't know who's listening. Why should my code, then, depend on wether someone is listening or not?

# Adi Robinson said on June 18, 2004 3:28 AM:
This is an implementation of the NullObject pattern, which has some applicability in some situations, but admittedly not all. Checking for null is very action orientated when really the <b>intention</b> of the eventing class is to simply tell listening observers about a particular event. O-O in general has it's costs, in C# just as much as any language, especially with the dynamic dispatch. PErsonally, I do do a check for null. If you want to make the code more intention revealing I'd proabbly do a extract method refactoring or introduce explaining variable:

...
bool thereArePriceUpdateListeners = (PriceUpdate != null ) ;

if ( thereArePriceUpdateListeners ) {
OnPriceUpdate(...) ;

This makes the code more readable, the intentions are clear and no dynmaic dispatch costs.

An alternative pattern is to use the State pattern to achieve the same goal.
# Jim Argeropoulos said on June 18, 2004 5:38 AM:
Simpler, so better.

I was talking with someone about C#'s baked in robustness last night. This is one area where they missed the boat.

Like you, I would gladly take robustness over "potential" performance issues. Now if only I could do this in my code today!
# Ron said on June 18, 2004 8:16 AM:
I agree with the other comments, the null check for events should be built into the Framework. However, this is a nice workaround. Too bad it has to wait for VS2005 in order to do this "cleanly".
# Udo said on June 30, 2004 4:23 AM:
Why I cant compile this?
In the line
public event System.EventHandler MyEvent = delegate { };
the compiler says "Invalid expression term 'delegate'(C1525)". Have you got a running full example?
Thanks
# jaybaz [MS] said on June 30, 2004 5:22 PM:
Udo: You'll need Whidbey (VS 2005) to do this.

Try it out:

http://blogs.msdn.com/jaybaz_ms/archive/2004/06/29/168872.aspx
# jaybaz [MS] WebLog said on September 16, 2004 7:52 PM:
# Hackward and Foreword said on October 3, 2004 2:54 PM:
# Hackward and Foreword said on October 31, 2004 3:26 PM:
# Conchoid » Blog Archive » Dealing with lazy design habits said on March 21, 2006 2:47 PM:
PingBack from http://www.conchoid.com/2006/03/21/dealing-with-lazy-design-habits/
New Comments to this post are disabled
Page view tracker