a.toraby
a.toraby

Reputation: 3391

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

What is the difference between these two code samples for invoking an event?

Sample 1

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

Sample 2

DataChanged.Invoke(this);

When should I use each method to invoke a custom event? And why sometimes I get a NullReferenceException when I try to invoke event using DataChanged.Invoke(this), but when I convert the event invocation to the method in Sample 1 the DataChanged never becomes null anymore?

Upvotes: 7

Views: 4332

Answers (5)

Dinesh Chaudhary
Dinesh Chaudhary

Reputation: 1

An Example:

public void OnAbc(){
    var data=Abc;

    if(!String.IsNullOrEmpty(data))
        Abc(sender,e);
}

Upvotes: 0

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391276

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.

Upvotes: 19

J. Swietek
J. Swietek

Reputation: 405

Are you sure, that in Sample 1 the DataChanged is never null? Or you just don't get the NullReference Exception (because you check if DataChanged is not null in the if statement)?

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

Now, why do we need to check for null reference (like in sample 1). Basically, when you invoke an event, you invoke all methods that were subscribed to this event (e.g. DataChanged += someEventHandler). If nobody subscribed to this event, it will have a null value. No method was assigned to handle this event. In other words: the event handler is null.

That's why it's a good practice to check for null, before invoking an event.

Upvotes: 1

Callum Bradbury
Callum Bradbury

Reputation: 956

If nothing has subscribed to DataChanged it will be set to null, and so when you attempt to do DataChanged.Invoke(this) you'll get a NullRefException as really it's trying to do null.Invoke(this). The reason for the additional if (DataChanged != null) is to avoid this occurring when nobody has subscribed to the event.

I don't believe that when you use Sample 1 DataChanged is never null, it's just never reaching the .Invoke to throw up the exception. It will always be null if nobody has subscribed.

Upvotes: 2

CodeCaster
CodeCaster

Reputation: 151588

when I convert the event invocation to the method in Sample 1 the DataChanged never becomes Null

Then you're simply looking at two different scenarios.

if you don't declare an event like public event EventHandler YourEvent = delegate { };, then YourEvent is null until some consumer subscribes to it.

Upvotes: 2

Related Questions