Object is null, but I can access a property without a Null Reference Exception

I have a really weird thing happening that I can’t figure out. I set a variable _redTeam.AttackMVP, but then when I check the results, the AttackMVP.Name is accessible and correct, but the AttackMVP itself is null.

This code:

 if(piece.ID==redAttackMVP)
{
_redTeam.AttackMVP=piece;
Debug.Log("piece="+_redTeam.AttackMVP);
Debug.Log("setredattackmvp="+_redTeam.AttackMVP.Name);
}

Yields this result in the log:
“piece = null”
“set red attack mvp = venonat”

How is this possible?

Is the AttackMVP class derived from a Monobehavior?
Can you post the class definition.

It could just be that Debug.Log has no way to print out a string value for whatever class Piece and AttackMVP are, especially if they aren’t derived from MonoBehaviour

AttackMVP definitely derives from UnityEngine.Object base. This is the result of the equality operator override. Unity Blog

AttackMVP is an instance of the class Piece, which inherits from MonoBehaviour.

public class Piece : MonoBehaviour

@kru - that is very interesting, had never seen it before. So it seems in this case, it is because the GameObject gets destroyed, but the class data remains intact. So the null check returns true, because it’s using the “fake null” check. While the class data is actually there.

That’s it exactly. You have kicked over a stone and discovered a bit of very dark (yet darned convenient) magic in the Unity environment. Now that you know about it, you can safely put it to use.

Just be aware that this method:

==

is static. This means that if you’ve got two UnityEngine.Objects that you’re comparing with ==, but you’ve referenced them through System.Object or (more likely!) some interface, the magic null check will not happen, as the call will dispatch to System.Object.== instead of UnityEngine.Object.==

Example:

IEnumerator Start() {
    GameObject go1 = new GameObject();

    object o1 = go1;

    Debug.Log(go1 == null); //false
    Debug.Log(o1 == null); //false

    yield return null; //wait a frame

    Destroy(go1);

    //Destroy happens end-of-frame, so wait another!
    yield return null; 

    Debug.Log(go1 == null); //true
    Debug.Log(o1 == null); //false!
}
1 Like

Does your piece class overwrite ToString?