Why does C# null-conditional operator not work with Unity serializable variables?

It does not work in general with anything inheriting from UnityEngine.Object!

It is bypassed due to how they internally implemented the ==/!= method differently. See Custom == operator, should we keep it?

ReSharper explained it pretty well in Possible unintended bypass of lifetime check of underlying Unity engine object

This warning is shown if a type deriving from UnityEngine.Object uses either the null coalescing (??) or null propagation or conditional (?.) operators. These operators do not use the custom equality operators declared on UnityEngine.Object, and so bypass a check to see if the underlying native Unity engine object has been destroyed. An explicit null or boolean comparison, or a call to System.Object.ReferenceEquals() is preferred in order to clarify intent.

UnityEngine.Object is in some occasions not really null but still keeps some meta data. So the underlying object(= System.Object) is not null, UnityEngine.Object‘s overwritten == operator just returns true for == null.

The main reason why therefore things like _tickIcon?.gameObjct throw a NullReferenceException is that the ?. operator only directly works on the underlying object(System.Object) while the UnityEngine.Object works with their custom implementation on a different level.

E.g. after

Destroy(_tickIcon);
_tickIcon.SetActive(false);

you will note that you don’t get a normal NullReferenceException which would be the case if it were actually null but rather get a Unity customs MissingReferenceException telling you a probable reason for why the exception was thrown.


Long story short: As solution UnityEngine.Object has the implicit bool operator

Does the object exist?

The example given there is actually not really true – see above

You should always check the existence of anything derived from UnityEngine.Object like this:

if(_tickIcon)
{
    _tickIcon.SetActive(false);
}

Leave a Comment