Sunday, November 16, 2008

Empty delegate makes event raising easy and thread-safe

I'm currently working on a project that will use some of the guidelines from the WPF Composite Application Guidance. And as I was studying the source code I kept seeing a strange
initialization of events that looked something like this;
public event EventHandler EmptyDelegateEvent = delegate { };
I mean; I do know my way around delegates, but these empty delegates puzzled me. After googling around a bit I found that this was a just a clever way of avoiding null reference exception when raising the event. So instead of this;
public event EventHandler CheckForNullEvent;

void RaiseEvent()
  // the usuall way
  if (CheckForNullEvent != null)
    CheckForNullEvent(this, new EventArgs());
} can simply do this;
public event EventHandler EmptyDelegateEvent = delegate { };

void RaiseEvent()
   // the easy way
   EmptyDelegateEvent(this, new EventArgs());
When using empty delegates you can simply raise the event without checking for null. Note though, that performance wise it will be better to do the "if not null" check than a "delegate {}". But I ran some performance testing to compare the two, and the performance hit is really not that big of an issue. Even though the performance of the empty delegate was 20-30% slower than the null check, the time it takes to do either of them is miniscule. This is really not where you should put your performance tuning effort. A 'null reference exception', which is much more likely to happen if you forget to check for the null, will have a much bigger impact on the overall performance of your application. Or even worse; if a raise condition occurs. Which again reminds me that the correct way of checking the event for null and at the same time making sure it's thread-safe, is this;
void RaiseEvent()
   // the thread-safe way
   EventHandler copyOfEvent = CheckForNullEvent;
   if (copyOfEvent != null)
       copyOfEvent(this, new EventArgs());
And how many does actually do that? And talking of performance; what about 'developer performance'? Instantiating an empty delegate and no need for null checking or possible raise conditions, means faster coding and less bugs - e.g. better developer performance.


Hi, and welcome to my blog!

I’m a .NET developer working for the Trondheim-based company Sentinel Software, where we're building the next generation sales-support tool for car dealers.

I started out in this geekie world as a database/web developer on Microsoft SQL Server 2000 and classic ASP. And even though I still enjoy programming intricate joins in T-SQL, since I was introduced to .NET and C# in 2001 I have never missed classic ASP.

In my early days as a .NET-developer I mainly worked on ASP.NET WebForms. Later I moved over on the desktop and starting building WinForms, but still with some ASP.NET work occasionally. Since late 2007 I've been fortunate enough to work on WPF and I must say that I'm immensely pleased with this framework and hopefully I’m all done with WinForms.   

Strongly influenced by my former colleague Pål Fossmo I’ve also developed a strong feeling for Test Driven Development. What I really enjoy about TDD is the confidence that testing gives me. It makes me sleep better at night knowing that the code I wrote today has been proven to work and I didn’t mess up any other parts of the application writing it.

Closely related to the awakening experience of testable code is my interest in design patterns and beautiful code. These three pillars – testable, pattern based, well-written code – are what I consider the very core of developing good, maintainable software. I believe that one of my main responsibilities as a developer is to make whatever code I write understandable and thereby maintainable to the guy or gal next to me. Because when I move on to the next project/job, (s)he is the one who’s going to maintain and build on to the code I just left behind. Taking pride in making that an as easy job as possible is always my number one priority.

I was awarded an Microsoft MVP in C# in July 2014.