Init(args) has been designed with inversion of control in mind and aims to make it as easy as possible to work with interfaces instead of specific classes in Unity.
One pain point when using interfaces in Unity is that checking them for null can be problematic. This is because in addition to being actually null, Objects in Unity can also be destroyed. You usually don’t even notice the difference when working with specific classes directly, because the Object class has a custom == operator which internally also checks whether the Object has been destroyed. However when an Object has been assigned to an interface type variable and this is compared against null, the overloaded == operator does not get used. This can result in null reference exceptions when trying to access the members of a destroyed Object.
Player player = FindAnyObjectByType<Player>(); IPlayer iplayer = player as IPlayer; Destroy(player); Debug.Log(player == null); // Prints true Debug.Log(iplayer == null); // Prints false
Player player = FindAnyObjectByType<Player>(); IPlayer iplayer = player as IPlayer; Destroy(player); Debug.Log(player == null); // Prints true Debug.Log(iplayer == null); // Prints false Debug.Log(iplayer == Null); // Prints true
It is also possible to utilize this safe null checking inside classes that don’t derive from any of the base classes in Init(args) by importing the static members of the NullExtensions class.
using UnityEngine; using static Sisus.NullExtensions; public static class PlainOldClass { public static void Example() { Player player = Object.FindAnyObjectByType<Player>(); IPlayer iplayer = player as IPlayer; Object.Destroy(player); Debug.Log(player == null); // Prints true Debug.Log(iplayer == null); // Prints false Debug.Log(iplayer == Null); // Prints true } }
In addition to the Null property there’s also a new NullOrInactive property. This functions identically to the Null property but also checks if the Object is a component on an inactive GameObject.
Player player = FindAnyObjectByType<Player>(); IPlayer iplayer = player as IPlayer; player.gameObject.SetActive(false); Debug.Log(player.gameObject.activeInHierarchy); // Prints true Debug.Log(iplayer == NullOrInactive); // Prints true
This functionality can be particularly useful when utilizing Object Pooling and an inactive GameObject is meant to represent an object which doesn’t exist.