8
votes
\$\begingroup\$

I often see this for custom events:

void InvokeCustomEvent(EventArgs e)
{
    var handler = CustomEvent;
    if (handler != null) handler(this, e);
}

But is creating the handler variable required, best practice, or superfluous, when compared to:

void InvokeCustomEvent(EventArgs e)
{
    if (CustomEvent != null) CustomEvent(this, e);
}

?

\$\endgroup\$
  • \$\begingroup\$ IMO, it should be moved to StackOverflow, though I believe this question is already present there. \$\endgroup\$ – Snowbear Mar 4 '11 at 9:19
  • \$\begingroup\$ @Snowbear: Yep, there's this one. I should have checked... \$\endgroup\$ – MPelletier Mar 4 '11 at 11:57
15
votes
\$\begingroup\$

But is creating the handler variable required, best practice, or superfluous, when compared to:

Yes, it is needed. Otherwise, CustomEvent could be set to null after you've checked for null, but before you've invoked it. This can happen if it gets set in another thread, or if one of the event handlers unregisters itself or another one.

I usually have this declared somewhere in my codebase:

public static class EventExtensions
{
    public static void Raise<T>(this EventHandler<T> handler, T args) {
        if (handler != null) handler(args);
    }
}

Now, with any event handler, you can just do:

handler.Raise(args);

You can call an extension method with a null this, so it will do the right thing even if handler is null. Furthermore, by copying handler into the local variable used by Raise, you automatically get the copy you need to make sure the handler won't disappear under you. Works like a charm.

\$\endgroup\$
  • 1
    \$\begingroup\$ Too bad the inventers of C# didn't simply make that the default behavior for invoking an event. Mind boggling to me that they didn't, since invoking an event with no subscribers should be a perfectly legitimate "do nothing" operation. \$\endgroup\$ – supercat Mar 3 '11 at 23:36
  • 1
    \$\begingroup\$ There is no concept of "an event with no subscribers". When you create an object that has some event fields, they will be null to begin with. When you register the first handler with myObj.SomeEvent += SomeHandler, that += is creating a new EventHandler object from scratch. This way an object doesn't pay a price for instantiating empty EventHandlers on creation if it never uses them. Does make them a bit uglier to use though. :( \$\endgroup\$ – munificent Mar 4 '11 at 1:45
  • 1
    \$\begingroup\$ My initial (and maybe a bit naive) belief was pretty much like what @supercat wants, that the event at least registered "transparently" a base, "do nothing" operation. \$\endgroup\$ – MPelletier Mar 4 '11 at 3:04
  • 1
    \$\begingroup\$ @MPelletier: That might be nice, but that means you'd have to create the EventHandler to begin with. Imagine you have a class with fifty events on it. When you instantiate that class, it won't waste any time touching them. They'll just all be null fields. The first time you register a handler on one of them using +=, it will get created. That way you don't pay the price of constructing a bunch of unused EventHandlers every time you create an object. What you propose might be a better idea, but you'd lose that performance advantage. \$\endgroup\$ – munificent Mar 4 '11 at 23:42
  • \$\begingroup\$ Seems I can't call this extension method on more specific kinds of EventHandler<T> like PropertyChangedEventHandler. This makes it not so useful I think. \$\endgroup\$ – HappyNomad Jul 18 '13 at 21:17
8
votes
\$\begingroup\$

You actually don't need the null check at all if you use the following trick. Simply create a default, empty handler that is always registered, so the event is guaranteed to never be null.

Declare your event like so (notice the = delegate { } bit)

public event EventHandler CustomEvent = delegate { };

And you can then invoke it without any null checks.

\$\endgroup\$
  • \$\begingroup\$ I like this answer (and choosing was truly heart-breaking) for its simplicity. I'd rather do this in cases of a very light structure, and not, as suggested above, dozens of events in many instances of the same class. \$\endgroup\$ – MPelletier Mar 5 '11 at 3:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.