Why should I check for null before calling a custom event?

What is the difference between these two code examples for triggering an event?

Example 1

public void OnDataChanged() { if (DataChanged != null) { DataChanged(this); } } 

Sample 2

 DataChanged.Invoke(this); 

When should I use each method to trigger a custom event? And why sometimes I get a NullReferenceException when trying to raise an event using DataChanged.Invoke(this) , but when I convert the event call to the method in Example 1, DataChanged no longer become null?

+4
source share
5 answers

The 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 several reasons for this form:

  • Checking if evt != null ensures that we will not try to call the null delegate. This can happen if no one has connected an event handler to the event.
  • In a multi-threaded scenario, since the delegates are immutable, as soon as we get a local copy of the delegate in evt , we can safely call it after checking for a non-zero value, because after but before the call.

What to pass for e is different if you need to pass a child of EventArgs 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 often it is:

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

This syntax is:

 evt(sender, e); 

is just another way to write this:

 evt.Invoke(sender, e); 

Also note that the event is an event from outside your class, only add or remove event handlers can be processed from it.

Inside your class, an event is a delegate, you can call it, check the target or method, view the list of subscribers, etc.


In addition, a new ?. Operator is introduced in C # 6 ?. - Null-conditional operator - which is mostly not suitable for if not-null, dereference , which may shorten this method:

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

in it:

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

which can be further abbreviated using elements expressed by:

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

Please note that this is not possible to write:

 XYZ?.(sender, e); 

therefore, in this case, you must use Invoke yourself.

+13
source

when I convert an event call to a method in example 1, DataChanged never becomes Null

Then you just look at two different scenarios.

if you do not declare an event such as public event EventHandler YourEvent = delegate { }; , then YourEvent is null until some user signs it.

+2
source

If nothing subscribes to DataChanged, it will be set to null, and so when you try to execute DataChanged.Invoke (this), you will get a NullRefException, because it really is trying to execute null.Invoke (this). The reason for the extra if (DataChanged! = Null) is to avoid this when no one has subscribed to the event.

I do not believe that when you use Sample 1 DataChanged, it is never null, it just never reaches .Invoke to raise an exception. It will always be zero if no one has signed up.

+1
source

Are you sure that in Example 1, DataChanged never null? Or you just don't get a NullReference Exception (because you are checking, not << β†’ << β†’

Let's start with the basics. An event is a special kind of delegate. When you call DataChanged (this) and DataChanged.Invoke (this), it is the same. What for? Because it compiles to the same thing. So all DataChanged(this) is just a shorthand for calling DataChanged.Invoke(this) .

Now, why do we need to check the null reference (as in example 1). Basically, when you call an event, you call all the methods that subscribed to this event (e.g. DataChanged += someEventHandler ). If no one has subscribed to this event, it will be null . No method has been assigned to handle this event. In other words: the event handler is null.

This is why it is good practice to check for null before raising an event.

+1
source

Example:

 public void OnAbc(){ var data=Abc; if(!String.IsNullOrEmpty(data)) Abc(sender,e); } 
0
source

All Articles