Use of Null Check in Event Handler

Use of null check in event handler

It's really not clear what you mean I'm afraid, but if there's the possibility of the delegate being null, you need to check that separately on each thread. Typically you'd do:

public void OnSeven()
{
DivBySevenHandler handler = EventSeven;
if (handler != null)
{
handler(...);
}
}

This ensures that even if EventSeven changes during the course of OnSeven() you won't get a NullReferenceException.

But you're right that you don't need the null check if you've definitely got a subscribed handler. This can easily be done in C# 2 with a "no-op" handler:

public event DivBySevenHandler EventSeven = delegate {};

On the other hand, you might want some sort of locking just to make sure that you've got the "latest" set of handlers, if you might get subscriptions from various threads. I have an example in my threading tutorial which can help - although usually I'd recommend trying to avoid requiring it.

In terms of garbage collection, the event publisher ends up with a reference to the event subscriber (i.e. the target of the handler). This is only a problem if the publisher is meant to live longer than the subscriber.

Why should I check for null before I invoke the custom event?

An OnXYZ method should always follow this form:

public void OnXYZ()
{
var evt = XYZ;
if (evt != null)
evt(sender, e); // where to get e from differs
}

There are a couple of reasons for this form:

  1. The if evt != null check ensures that we don't try to invoke a null delegate. This can happen if nobody has hooked up an event handler to the event.
  2. In a multithreaded scenario, since delegates are immutable, once we've obtained a local copy of the delegate into evt, we can safely invoke it after checking for non-null, since nobody can alter it after the if but before the call.

What to pass for e differs, if you need to pass an EventArgs descendant with a parameter there are two ways:

public void OnXYZ(string p)
{
var evt = XYZ;
if (evt != null)
evt(sender, new SomeEventArgs(p));
}

or more commonly this:

public void OnXYZ(SomeEventArgs e)
{
var evt = XYZ;
if (evt != null)
evt(sender, e);
}

This syntax:

evt(sender, e);

is just a different way of writing this:

evt.Invoke(sender, e);

Also note that externally to your class, the event is an event, you can only add or remove event handlers from it.

Internal to your class, the event is a delegate, you can invoke it, check the target or method, walk the list of subscribers, etc.


Also, in C# 6 there is a new operator introduced, ?. - the Null-conditional operator - which is basically short for if not-null, dereference, which can shorten this method:

public void OnXYZ(SomeEventArgs e)
{
var evt = XYZ;
if (evt != null)
evt(sender, e);
}

into this:

public void OnXYZ(SomeEventArgs e)
{
XYZ?.Invoke(sender, e);
}

which can be further shortened with the use of Expression-bodied members:

public void OnXYZ(SomeEventArgs e) => XYZ?.Invoke(sender, e);

Please note that it is not possible to write this:

XYZ?.(sender, e);

so you must in this case use Invoke yourself.

Checking if the handler != null vs Checking if the event != null in C#

Both are checking to see if the delegate associated with the event is null.

The purpose of storage into the local is to prevent a TOCTOU-style race in multithreaded code.

It is important to note that using a local only eliminates one of two potential races. See my 2009 article on the subject for details: http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx

and also this question:

C# Events and Thread Safety

What is the event handler check for not being null?

Quite simply, if no delegate has yet been assigned to a particular event handler, it will be null, and trying to invoke it will cause a NullReferenceException.

Doing a null check before invoking it prevents this NullReferenceException from occurring.

Why does C# require you to write a null check every time you fire an event?

It's certainly a point of annoyance.

When you write code which accesses a field-like event within a class, you're actually accessing the field itself (modulo a few changes in C# 4; let's not go there for the moment).

So, options would be:

  • Special-case field-like event invocations so that they didn't actually refer to the field directly, but instead added a wrapper
  • Handle all delegate invocations differently, such that:

    Action<string> x = null;
    x();

    wouldn't throw an exception.

Of course, for non-void delegates (and events) both options raise a problem:

Func<int> x = null;
int y = x();

Should that silently return 0? (The default value of an int.) Or is it actually masking a bug (more likely). It would be somewhat inconsistent to make it silently ignore the fact that you're trying to invoke a null delegate. It would be even odder in this case, which doesn't use C#'s syntactic sugar:

Func<int> x = null;
int y = x.Invoke();

Basically things become tricky and inconsistent with the rest of the language almost whatever you do. I don't like it either, but I'm not sure what a practical but consistent solution might be...

Event handler and null-conditional operator

should I copy event ProperyChanged to local variable, if I use null-conditional operator?

No, there's no need. In fact, one of the main reasons the null-conditional operator was introduced was to simplify code using this pattern. It has the same effect as copying the source value to a local variable and inherently avoids the "check and use" concurrency trap that the "copy to local variable" technique is intended to address.

See related posts:

Invoking Events, h(args) vs EventName?.Invoke() (almost an exact duplicate…it does approach the question from a slightly different angle though)

Why should I check for null before I invoke the custom event?

Raising C# events with an extension method - is it bad?

Is there any reason to assign an event to a local variable before raising it?

Why would a 'public event EventHandler cccc' be null?

The event handler will be null unless somebody has subscribed to the event. As soon as a delegate is subscribed to the event, it will no longer be null.

This is why it's always suggested to use the following form for raising events:

public void Start()
{
var handler = this.StartedWorking;
if (handler != null)
{
handler(this, eventArgObject);
}
}

This protects you from a null exception if there has been no subscribers.

In C#, why can't I test if a event handler is null anywhere outside of the class that it's defined?

An event is really just an "add" operation and a "remove" operation. You can't get the value, you can't set the value, you can't call it - you can just subscribe a handler for the event (add) or unsubscribe one (remove). This is fine - it's encapsulation, plain and simple. It's up to the publisher to implement add/remove appropriately, but unless the publisher chooses to make the details available, subscribers can't modify or access the implementation-specific parts.

Field-like events in C# (where you don't specify the add/remove bits) hide this - they create a variable of a delegate type and an event. The event's add/remove implementations just use the variable to keep track of the subscribers.

Inside the class you refer to the variable (so you can get the currently subscribed delegates, execute them etc) and outside the class you refer to the event itself (so only have add/remove abilities).

The alternative to field-like events is where you explicitly implement the add/remove yourself, e.g.

private EventHandler clickHandler; // Normal private field

public event EventHandler Click
{
add
{
Console.WriteLine("New subscriber");
clickHandler += value;
}
remove
{
Console.WriteLine("Lost a subscriber");
clickHandler -= value;
}
}

See my article on events for more information.

Of course the event publisher can also make more information available - you could write a property like ClickHandlers to return the current multi-cast delegate, or HasClickHandlersto return whether there are any or not. That's not part of the core event model though.

Checking for null before event dispatching... thread safe?

In C# 6.0 you can use monadic Null-conditional operator ?. to check for null and raise events in easy and thread-safe way.

SomeEvent?.Invoke(this, args);

It’s thread-safe because it evaluates the left-hand side only once, and keeps it in a temporary variable. You can read more here in part titled Null-conditional operators.



Related Topics



Leave a reply



Submit