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?