Is there a downside to adding an anonymous empty delegate on event declaration?

C#Coding StyleDelegatesEventsIdioms

C# Problem Overview


I have seen a few mentions of this idiom (including on SO):

// Deliberately empty subscriber
public event EventHandler AskQuestion = delegate {};

The upside is clear - it avoids the need to check for null before raising the event.

However, I am keen to understand if there are any downsides. For example, is it something that is in widespread use and is transparent enough that it won't cause a maintenance headache? Is there any appreciable performance hit of the empty event subscriber call?

C# Solutions


Solution 1 - C#

Instead of inducing performance overhead, why not use an extension method to alleviate both problems:

public static void Raise(this EventHandler handler, object sender, EventArgs e)
{
    if(handler != null)
    {
        handler(sender, e);
    }
}

Once defined, you never have to do another null event check again:

// Works, even for null events.
MyButtonClick.Raise(this, EventArgs.Empty);

Solution 2 - C#

For systems that make heavy use of events and are performance-critical, you will definitely want to at least consider not doing this. The cost for raising an event with an empty delegate is roughly twice that for raising it with a null check first.

Here are some figures running benchmarks on my machine:

For 50000000 iterations . . .
No null check (empty delegate attached): 530ms
With null check (no delegates attached): 249ms
With null check (with delegate attached): 452ms

And here is the code I used to get these figures:

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
	class Program
	{
		public event EventHandler<EventArgs> EventWithDelegate = delegate { };
		public event EventHandler<EventArgs> EventWithoutDelegate;

		static void Main(string[] args)
		{
			//warm up
			new Program().DoTimings(false);
			//do it for real
			new Program().DoTimings(true);

			Console.WriteLine("Done");
			Console.ReadKey();
		}

		private void DoTimings(bool output)
		{
			const int iterations = 50000000;

			if (output)
			{
				Console.WriteLine("For {0} iterations . . .", iterations);
			}

			//with anonymous delegate attached to avoid null checks
			var stopWatch = Stopwatch.StartNew();

			for (var i = 0; i < iterations; ++i)
			{
				RaiseWithAnonDelegate();
			}

			stopWatch.Stop();

			if (output)
			{
				Console.WriteLine("No null check (empty delegate attached): {0}ms", stopWatch.ElapsedMilliseconds);
			}


			//without any delegates attached (null check required)
			stopWatch = Stopwatch.StartNew();

			for (var i = 0; i < iterations; ++i)
			{
				RaiseWithoutAnonDelegate();
			}

			stopWatch.Stop();

			if (output)
			{
				Console.WriteLine("With null check (no delegates attached): {0}ms", stopWatch.ElapsedMilliseconds);
			}


			//attach delegate
			EventWithoutDelegate += delegate { };


			//with delegate attached (null check still performed)
			stopWatch = Stopwatch.StartNew();

			for (var i = 0; i < iterations; ++i)
			{
				RaiseWithoutAnonDelegate();
			}

			stopWatch.Stop();

			if (output)
			{
				Console.WriteLine("With null check (with delegate attached): {0}ms", stopWatch.ElapsedMilliseconds);
			}
		}

		private void RaiseWithAnonDelegate()
		{
			EventWithDelegate(this, EventArgs.Empty);
		}

		private void RaiseWithoutAnonDelegate()
		{
			var handler = EventWithoutDelegate;

			if (handler != null)
			{
				handler(this, EventArgs.Empty);
			}
		}
	}
}

Solution 3 - C#

The only downside is a very slight performance penalty as you are calling extra empty delegate. Other than that there is no maintenance penalty or other drawback.

Solution 4 - C#

If you are doing it a /lot/, you might want to have a single, static/shared empty delegate that you re-use, simply to reduce the volume of delegate instances. Note that the compiler caches this delegate per event anyway (in a static field), so it is only one delegate instance per event definition, so it isn't a huge saving - but maybe worthwhile.

The per-instance field in each class will still take the same space, of course.

i.e.

internal static class Foo
{
    internal static readonly EventHandler EmptyEvent = delegate { };
}
public class Bar
{
    public event EventHandler SomeEvent = Foo.EmptyEvent;
}

Other than that, it seems fine.

Solution 5 - C#

It is my understanding that the empty delegate is thread safe, whereas the null check is not.

Solution 6 - C#

There is no meaningful performance penalty to talk about, except, possibly, for some extreme situations.

Note, however, that this trick becomes less relevant in C# 6.0, because the language provides an alternative syntax to calling delegates that may be null:

delegateThatCouldBeNull?.Invoke(this, value);

Above, null conditional operator ?. combines null checking with a conditional invocation.

Solution 7 - C#

I would say it's a bit of a dangerous construct, because it tempts you to do something like :

MyEvent(this, EventArgs.Empty);

If the client throws an exception, the server goes with it.

So then, maybe you do:

try
{
  MyEvent(this, EventArgs.Empty);
}
catch
{
}

But, if you have multiple subscribers and one subscriber throws an exception, what happens to the other subscribers?

To that end, I've been using some static helper methods that do the null check and swallows any exception from the subscriber side (this is from idesign).

// Usage
EventHelper.Fire(MyEvent, this, EventArgs.Empty);
    

public static void Fire(EventHandler del, object sender, EventArgs e)
{
    UnsafeFire(del, sender, e);
}
private static void UnsafeFire(Delegate del, params object[] args)
{
    if (del == null)
    {
        return;
    }
    Delegate[] delegates = del.GetInvocationList();

    foreach (Delegate sink in delegates)
    {
        try
        {
            sink.DynamicInvoke(args);
        }
        catch
        { }
    }
}

Solution 8 - C#

Instead of "empty delegate" approach one can define a simple extension method to encapsulate the conventional method of checking event handler against null. It is described here and here.

Solution 9 - C#

One thing is missed out as an answer for this question so far: It is dangerous to avoid the check for the null value.

public class X
{
    public delegate void MyDelegate();
	public MyDelegate MyFunnyCallback = delegate() { }

	public void DoSomething()
	{
		MyFunnyCallback();
	}
}


X x = new X();

x.MyFunnyCallback = delegate() { Console.WriteLine("Howdie"); }

x.DoSomething(); // works fine

// .. re-init x
x.MyFunnyCallback = null;

// .. continue
x.DoSomething(); // crashes with an exception
 

The thing is: You never know who will use your code in which way. You never know, if in some years during a bug fix of your code the event/handler is set to null.

Always, write the if check.

Hope that helps ;)

ps: Thanks for the performance calculation.

pps: Edited it from a event case to and callback example. Thanks for the feedback ... I "coded" the example w/o Visual Studio and adjusted the example I had in mind to an event. Sorry for the confusion.

ppps: Do not know if it still fits to the thread ... but I think it is an important principle. Please also check another thread of stackflow

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionserg10View Question on Stackoverflow
Solution 1 - C#Judah Gabriel HimangoView Answer on Stackoverflow
Solution 2 - C#Kent BoogaartView Answer on Stackoverflow
Solution 3 - C#MauriceView Answer on Stackoverflow
Solution 4 - C#Marc GravellView Answer on Stackoverflow
Solution 5 - C#Christopher BennageView Answer on Stackoverflow
Solution 6 - C#Sergey KalinichenkoView Answer on Stackoverflow
Solution 7 - C#Scott PView Answer on Stackoverflow
Solution 8 - C#vkelmanView Answer on Stackoverflow
Solution 9 - C#ThomasView Answer on Stackoverflow