0

In short, I'm wondering of C#'s null propagation will safely allow me to avoid a race condition when signaling an event which would otherwise require a local variable.

To illustrate, consider the following class which exposes an event ("FooEvent" and 3 different ways of signaling it.

using System;

public class FooArgs
{

}
public class Foo
{
    public event EventHandler<FooArgs> FooEvent;

    public Foo()
    {


    }
    public void SignalEvent()
    {
        // UNSAFE:  Race condition between checking null
        // and invoking event could lead to crash if client
        // unsubscribes in the interim. 

        if (FooEvent != null)
            FooEvent(this, new FooArgs());
    }

    public void SignalEvent2()
    {
        // SAFE:  Get event subscribers into a local and THEN
        // invoke to avoid race condition.

        var f = FooEvent;
        if (f != null)
            f(this, new FooArgs());
    }

    public void SignalEvent3()
    {
        // NULL PROPAGATION:  Is this safe or not?  Is the null 
        // checked before invoking each client or only once?

        FooEvent?.Invoke(this, new FooArgs());
    }

}

The first method is unsafe because a a client could unsubscribe after check the null but before you invoke the handler.

The second method is safe because you get a local copy of the subscribers first.

The third method is the most verbose and is appealing. It also is what I've seen recommended many times. But its safety all hinges on when the null propagation is truly checked. What if 2 clients are subscribed and between the time my Notify() is called for the first and second, the second one unsubscribes. Does null propagation check before each client or just once?

Joe
  • 5,394
  • 3
  • 23
  • 54
  • Maybe somebody can enlighten me, but isn't this what [locks](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement) are for? Wouldn't you not have to worry about any of this with a lock? – Scott Oct 12 '17 at 18:32
  • 1
    If you want to know if the null propagation operator evaluates the expression multiple times just invoke it on something that causes side effects, and see if those side effects happen multiple times. – Servy Oct 12 '17 at 18:35
  • Scott I don't think that's necessarily a help. What if notifying one client triggers another client to unsubscribe? All on the same thread. (Not a design I'd want, mind you, but I'm coding for safety here) – Joe Oct 12 '17 at 18:37
  • Thanks, Servy. My Search-Fu was clearly not up to the task – Joe Oct 12 '17 at 18:40
  • @Joe That wouldn't be a problem at all, as locks are reentrant, and it's also not uncommon, I've written lots of event handlers that unsubscribe from the event in the handler, it's a common pattern. The *actual* problem with locks that approach is that it's just a lot more work than is actually needed to solve the problem – Servy Oct 12 '17 at 18:40
  • @Joe You mean copy-pasting the title of your question, unedited, into Google? – Servy Oct 12 '17 at 18:41
  • 1
    Look, the original title of my question was "C# events and race conditions". I did search for that and it did not find the answer you linked to. But right after I created the question, I retitled it to include the work "null-propagation". I admit I did not search for the retitled term, but then again my question had already been asked and I didn't think it would help. Nice of you to vote me down after I voted you up but never miss a chance to be snarky, I always sy. – Joe Oct 12 '17 at 18:46
  • Regarding the re-entrancy of locks, that would actually have been the problem, had my worry about null propagation been valid. Fortunately it is not – Joe Oct 12 '17 at 18:54

0 Answers0