Unity: Null Check Not Working?

Ever checked an object for null and it didn’t work? Computers do precisely what you tell them to do -> it must be a programming error that bypasses the null check.

 

This is one of the moments where I doubt my sanity as a programmer.

 

What Happened?

The C# target object isn’t null but the C++ object it pointed to is. In my case, the target is a MonoBehaviour referenced as an interface. The != operator, therefore, executed a pure C# null check instead of Unity’s custom null check which leads to the null reference exception.

 

 

Why?

Unity is a bit special when it comes to null checks. Most of the Unity engine is built in C++. The properties of GameObjects and UnityEngine.Objects live in the C++ part of the engine. The C# object only contains a pointer to the native C++ object.

 

The problem with this separation is, that the lifetime of the C++ and C# objects can be different because of memory management. The C++ object can already be destroyed while the C# object is still waiting for the garbage collector. The C# object isn’t null and passes the C# null check. But accessing it will lead to a null reference exception in the C++ engine.

 

To handle this problem Unity overloaded the == operator to return null for the C# object when the C++ native object is null.

 

This has a few problems:

 

  • It’s slow
  • Not thread-safe
  • Inconsistent behaviour with the ?? operator which does a pure C# null check.  (Should never be used with UnityEngine.Objects because of the above reason.)
  • It does not work when the object is boxed or referenced as an interface

 

Solution

The problem is that the compiler executed a C# null check instead of a Unity null check. This behaviour can be fixed in two ways:

  1. Don’t reference a UnityEngine.Object as interface or box it
  2. Cast it to UnityEnigne.Object before doing the null check.
if ((target as UnityEngine.Object) != null)
    target.OnPointerExit();