Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does C# null-conditional operator not work with Unity serializable variables?

I've noticed that if I have some variables exposed to the Unity inspector such as:

[SerializeField] GameObject _tickIcon;

If I leave them unassigned and try to use the null conditional operator and call a method on that object I get an exception saying the variable is not assigned. So basically instead of doing this:

_tickIcon?.SetActive(false);

It's forcing me to do this:

if(_tickIcon != null)
{
   _tickIcon.SetActive(false)
}

So I'm guessing this must be something specific to unity's runtime, it's not really null, but I can check for null and it work. I don't really understand this.

like image 444
user2000950 Avatar asked Jul 01 '20 13:07

user2000950


People also ask

Why does the letter C exist?

The letter c was applied by French orthographists in the 12th century to represent the sound ts in English, and this sound developed into the simpler sibilant s.

Why does C make two sounds?

History. This alternation is caused by a historical palatalization of /k/ which took place in Late Latin, and led to a change in the pronunciation of the sound [k] before the front vowels [e] and [i].

Why do people still use C instead of C++?

C++ is object-oriented, bottom-up, and includes many high-level features. C is low-level, procedural, and top-down. C is still in use because it is slightly faster and smaller than C++. For most people, C++ is the better choice.


1 Answers

It does not work in general with anything inheriting from UnityEngine.Object!

It is bypassed due to how they internally implemented the ==/!= method differently. See Custom == operator, should we keep it?

ReSharper explained it pretty well in Possible unintended bypass of lifetime check of underlying Unity engine object

This warning is shown if a type deriving from UnityEngine.Object uses either the null coalescing (??) or null propagation or conditional (?.) operators. These operators do not use the custom equality operators declared on UnityEngine.Object, and so bypass a check to see if the underlying native Unity engine object has been destroyed. An explicit null or boolean comparison, or a call to System.Object.ReferenceEquals() is preferred in order to clarify intent.

UnityEngine.Object is in some occasions not really null but still keeps some meta data. So the underlying object(= System.Object) is not null, UnityEngine.Object's overwritten == operator just returns true for == null.

The main reason why therefore things like _tickIcon?.gameObjct throw a NullReferenceException is that the ?. operator only directly works on the underlying object(System.Object) while the UnityEngine.Object works with their custom implementation on a different level.

E.g. after

Destroy(_tickIcon);
_tickIcon.SetActive(false);

you will note that you don't get a normal NullReferenceException which would be the case if it were actually null but rather get a Unity customs MissingReferenceException telling you a probable reason for why the exception was thrown.


Long story short: As solution UnityEngine.Object has the implicit bool operator

Does the object exist?

You should always check the existence of anything derived from UnityEngine.Object like this:

if(_tickIcon)
{
    _tickIcon.SetActive(false);
}

or explicit

if(_tickIcon != null)
{
    _tickIcon.SetActive(false);
}
like image 53
derHugo Avatar answered Oct 24 '22 01:10

derHugo