I wrote the following function to have a handy utility for sanity checks in my unity projects.
namespace MyProject.Utilities
{
public class DebugUtils
{
/// <summary>
/// Checks if passed object is null and prints to console if it is.
/// </summary>
/// <param name="obj">The obj.</param>
public static void DebugAssertNull<T>(T obj, string tag = "M_UTILS_DEBUG")
{
if (obj == null)
{
StackTrace stackTrace = new();
StackFrame stackFrame = stackTrace.GetFrame(1);
string methodName = stackFrame.GetMethod().Name;
string fileName = stackFrame.GetFileName();
int lineNumber = stackFrame.GetFileLineNumber();
string message = $"[{tag}] Object of type {typeof(T)} is null in method {methodName} at {fileName}:{lineNumber}";
UnityEngine.Debug.Assert(false, message);
}
}
}
}
Now when I call this function from another script as follows
public class SomeBehaviour: MonoBehaviour{
public GameObject someObject;
void Start(){
DebugAssertNull<GameObject>(someObject);
}
}
Now I am expecting that a message prints to the console. However upon running this code obj turns out to be not null. Using the debugger in Visual Studio 2019, setting up a watch obj == null
evaluates to true.
I feel like there is some implementation detail I am missing here. I am working with unity 2021, Visual Studio 2019, and .NET Framework 4.
2
Answers
It’s an old Unity… hmm… let’s call it a "feature" =)
The reason is that real Unity objects are in the C++ part and C# objects are only wrappers for these objects. That’s why the basic Unity3d object overrides
==
operator and returnstrue
in case of comparing with null even object still exists.You can find more information here
Just in addition to this answer
It works for me if you explicitly limit the type like e.g.
so apparently generics work different from what I would’ve expected as well and treat
T
like anobject
. In the upper it definitely uses the overloadUnityEngine.Object ==
.If this is intended to be used for stuff referenced in the Unity Inspector it should also be enough.
The only thing going by reference in the Inspector is
UnityEngine.Object
. Everything else is deserialized as values directly and nevernull
.Question would then be though why have such a debug tool for this case instead of simply checking directly
advantage of this would be: