C# ?. conditional invokation doesn't seem to work with gameobjects

This works:

if (reticle != null) reticle.SetActive(false);

where this does not:

reticle?.SetActive(false);

Is this just an unavoidable feature of Unity’s wrapping of gameobject and component referencing?

Unity overloads operator == to make certain objects compare as equal to null even when they’re not. This is most notably used for destroyed objects, but it also used for certain placeholder objects designed to provide extra debugging information (sometimes only inside the editor and not in the final build).

They are not allowed to override operators ?? or ?. in the same way.

So yes, basically you shouldn’t use ?? or ?. on Unity objects.

4 Likes

To further explain, every C# UnityEngine.Object is basically a wrapper to an unmanaged C++ counterpart. When you call Destroy() on a UnityEngine.Object the C++ object is deleted but in C# there is no concept of explicit object destruction, the only way managed objects are removed from memory is through garbage collection. All Unity can do is set pointer to the unmanaged C++ object inside the managed UnityEngine.Object to null.

During it’s early days, it was decided that Unity should overrode the UnityEngine.Object == operator so even if the managed UnityEngine.Object is not null, it returns true when compared to null if it’s internal pointer to the unmanaged object is null (aka: the object was destroyed at some point). This is more or less how a C++ smart pointer works, and allowed checking if an object was null or destroyed in a single statement.

As Antistone already mentioned, C# does not allow the ?? and ?. operators to be overridden, so they only check if the reference to the managed object is null, not if the object was destroyed.

Newer Unity-focused code analyzers for Visual Studio actually issue warnings when using ?. and ?? with Unity Object derived classes. Short of a new C# standard allowing overriding those operators, you should not use them with Unity objects.

2 Likes