Using the Null Conditional Operator

Using events in C# are pretty straight forward, but there has been a subtle problem that is often overlooked. A multicast delegate object is responsible for invoking all the attached handlers to an event. If there are no attached handlers, when the event is fired, a NullReferenceException will occur. The good news is that a new C# 6.0 feature makes solving this problem much simpler than previous options.
Take a look at a simple example of this problem.

    public class CableNews
    {
        public event EventHandler<string> newsReported;

        public void ReportNewsFlash(string news)
        {
            // Checking to see if the event handler is null before invoking it,
            // will solve the problem most of the time.
            if (newsReported != null)
            {
                newsReported(this, news);
            }
        }
    }

In cases where there are no attached handlers, the event will be null. When you work with a single threaded application, this quick check will solve the problem by not raising the event when no one is listening. Unfortunately, if multiple threads are involved, the listeners could unsubscribe between when the event is checked for null and when the event is invoked. There is a couple way to get around this prior to C# 6.0. Delegates are immutable, so you could create a temporary variable that held a reference to the event, and check the temporary variable to see if it’s null. The compiler could optimize away the temporary variable, so a call to Volatile.Read can be used to avoid that problem.

        EventHandler<string> temp = System.Threading.Volatile.Read(ref newsReported);
        if (temp != null) temp(this, news);

It works, it’s just kind of cumbersome. C# 6.0 introduces the NullConditionalOperator (“?.”) It evaluates the left-hand side of the operator to see if it is null. The expression on the right-hand side is executed when it is not null. Here’s an example of how to apply it to the eventing problem.

newsReported?.Invoke(this, news);

The Invoke method must be used because the compiler doesn’t allow a parentheses to follow the ?. Still, I think this is a much cleaner solution!

Leave a Reply

Your email address will not be published. Required fields are marked *