Is C# 6 ?. (Elvis op) thread safe? If so, how?

I want to clarify BJ Myers's (correct) answer.

In C# an event can be thought of as a field of delegate type -- just as a property can be thought of as a field of the property type -- and the value of that "field" can be null. If you are in the unfortunate situation of having an event handler being modified on one thread while another thread is attempting to invoke it, you can get into the situation where:

if (this.SomeEvent != null) 
    this.SomeEvent( ... );

is not threadsafe. The value could be mutated so that it is non-null before the check, null after the check, and the program crashes.

The usual way to make this "threadsafe", and I use the term advisedly, is to copy the value to a local and then test the local for null. This has the benefit of not crashing with a null dereference. However, the clever developer will note that there is still a race! The sequence can be

  • Non-null event handler cached on thread A
  • Event handler set to null on thread B
  • State needed by event handler is destroyed on thread B
  • Event handler runs on thread A and dies horribly

So in that sense this pattern is not "thread safe". If you are in this unfortunate position you are responsible for ensuring that the appropriate threading logic is implemented so that this cannot happen. You can do that however you want. If you want the (questionable) benefits of being able to call an event handler on one thread while mutating the event on another thread, then you've got to pay either to make it safe, or deal with race condition bugs.

I personally would avoid this situation like the plague, but I'm not smart enough to write correct multithreaded code.

Now, as for the actual question:

some_expression ?. ToString();

is the same as

temp = some_expression
temp == null ? null : temp.ToString()

Is the latter code "threadsafe" in your opinion?


From MSDN (emphasis mine):

Another use for the null-condition member access is invoking delegates in a thread-safe way with much less code. The old way requires code like the following:

var handler = this.PropertyChanged;
if (handler != null)
    handler(…)

The new way is much simpler:

PropertyChanged?.Invoke(e)

The new way is thread-safe because the compiler generates code to evaluate PropertyChanged one time only, keeping the result in temporary variable.

So there is no locking involved here - thread-safety is enforced by creating a local temporary variable, which prevents a different thread from modifying that variable in between the null check and some other operation.