- Home /
Difference in null behaviour between public/[SerializeField]private and private UnityEngine.Object
Hey all, relatively new to Unity so I apologize if this is common knowledge, but I was unable to find anything on this specific topic.
I was attempting to do an inline null check for a public Rigidbody2D
component before utilizing its velocity on another component, the simplified version looks essentially like this:
move += rigidBody2D is null ? new Vector2(0, player.velocity.y) : new Vector2(rigidBody2D.velocity.x, 0);
Strangely, I found when running tests for this, if rigidBody2D
wasn't assigned a value, it was throwing an error instead of evaluating true
at the null check and continuing appropriately. I did some poking around and ultimately disabled everything but a single GameObject in my project and threw this short test on it. It's worth noting that throughout this process, I purposely never assigned anything to the public
references (or the [SerializeField]private
references further down).
using UnityEngine;
public class UnityObjectPublicPrivateNullCheck : MonoBehaviour
{
private UnityEngine.Object privateUnityObjectNullCheck;
public UnityEngine.Object publicUnityObjectNullCheck;
private object privateSystemObjectNullCheck;
public object publicSystemObjectNullCheck;
void Start()
{
//null check on Unity object type
Debug.Log(privateUnityObjectNullCheck ?? true); //returns true, expected
Debug.Log(publicUnityObjectNullCheck ?? true); //returns false, huh???
//null check on System object type
Debug.Log(privateSystemObjectNullCheck ?? true); //returns true, expected
Debug.Log(publicSystemObjectNullCheck ?? true); //returns true, expected
}
}
This effectively gets my point across, but I did some further testing and found that public UnityEngine.Object
are not actually returning null
, but "null"
, whereas private System.Object
, public System.Object
, and private UnityEngine.Object
all return null
, expectedly.
One more additional test, I wagered a guess that this might have something to do with Unity's serialization for the inspector, so I went ahead and put this line in the script:
[SerializeField]private UnityEngine.Object serializedPrivateUnityObjectNullCheck;
...
//null check on Serialized private Unity object type
Debug.Log(serializedPrivateUnityObjectNullCheck ?? true); //returns false, huh???
Finding the culprit, I'm still a bit confused. Surely, this is this intended behaviour, but why? Am I destined to have to check for UnityEngine.Object.ToString() == "null"
for public
and [SerializeField] private
or is there a more efficient workaround?
Final note: I am running Unity 2020.1.17f1, not sure that matters.
Answer by tategarringer · Jan 01, 2021 at 09:44 AM
I was directed to a duplicate of this question on StackOverflow for anyone curious about this. Turns out, Unity has an overriden implementation of Equals
and null
, this link covers it and *why* in more depth. The solution is simply dropping the null comparison in favor of a boolean comparison when dealing with UnityEngine.Object
.
Answer by sacredgeometry · Jan 01, 2021 at 08:52 AM
Shouldnt move += rigidBody2D is null ? new Vector2(0, player.velocity.y) : new Vector2(rigidBody2D.velocity.x, 0);
be
move += rigidBody2D == null ? new Vector2(0, player.velocity.y) : new Vector2(rigidBody2D.velocity.x, 0);
Also no there isn't anything in the access modifier that would change the way null coalescing works what there is is that unitys editor adds a caching layer on-top of public fields. i.e. check what the value is in the inspector
I would argue that that's down to a stylistic preference because those both say the same thing, but that's not the question at hand anyways.
You are right I didnt realise they added null checking to is pattern matching.
p.s. I answered the question in the second part of the answer
Thanks for taking time to provide some clarity. Addressing the second part that i missed initially (sorry), this is still a bit confusing to me. I can understand the fact that Unity has implemented a custom method for returning null fields exposed to the editor, but I guess I'm curious as to why this would be preferable to just returning a legitimate null value? What's the workaround to checking UnityEngine.Object type for null values? Is there an already existing method for this that I'm unaware of that covers both System.Object null and UnityEngine.Object "null"?
Oh sorry I think I get what you mean now.
Unity overloads the equality operator (edit: sorry I havent slept probably shouldnt be trying to code)
https://blogs.unity3d.com/2014/05/16/custom-operator-should-we-keep-it/
It has its reasons but it may explain what you are seeing.
I was just redirected to a link on StackOverflow about this exact thing only moments before you posted this, so I went ahead and directed the answer to that. Thank you for taking time to post these links and help.