I currently have two scripts set up in Unity to handle some UI Audio. One is a manager and the other is there to play a sound for a specific UI element. A simplified version of what I have is this:
public class AudioUIManager : MonoBehaviour //Only one of these in the scene
{
public AudioClip genericUISound; //This is set in the inspector.
}
public class AudioUITextAnimation : MonoBehaviour
{
[SerializeField]
private AudioClip specifiedUISound; //This is not set in the inspector
[SerializeField]
private AudioUIManager audioUIManager; // I get a reference to this elsewhere
void Start()
{
//Use generic sounds from audio manager if nothing is specified.
specifiedUISound = specifiedUISound ?? audioUIManager.genericUISound;
print(specifiedUISound);
}
}
What I'm trying to achieve here is to have the specifiedUISound
field use the sound that it is assigned to it in the inspector. If no sound is assigned then use the generic sound from the UI manager. This saves me assigning the same sound to millions of buttons that require the same sound but gives me the option of having a specific sound for one button if I want to.
However, the null-coalessing operator is asigning null
to specifiedUISound
even though it is null and the audioUIManager
's sound is not. Also, I can get this to work if I use the ternary operator to check for null like so:
specifiedUISound = specifiedUIsound == null ? audioUIManager.genericUISound : specifiedUISound;
Am I misunderstanding the null coalescing operator? Why does this happen?
Edit: Jerry Switalski has pointed out that this only happens when the specifiedUISound
is serialized. (if it is public
or if it has the [SerializeField]
attribute). Can anyone shed some light on what is going on here?
You're running into Unity's custom equality operator:
While running in the editor, Unity replaces your serialized
null
with a sentinel value that isn't actuallynull
. This allows them to provide more informative error messages in some circumstances.Is
specifiedUISound
equal tonull
? That depends on how you ask. C# has multiple notions of "equality", including data equality and reference equality.Some checks will say the values are equal:
==
andObject.Equals
Others will say they are not equal:
??
andObject.ReferenceEquals
This behavior will only occur in the editor. When running in a standalone build, any
null
values will just benull
.It is not really complete answer to your question and very intresting example, but I ran few tests, and it looks like the problem is in
SerializeField
attribute.When I run this (
someObj
is assigned from inspectornullObj
is left empty):I have this prints:
However getting rid of
SerializeField
attribute, makes things work as intended:gives:
So reasuming:
I don't really know the root of the problem, but what is fact is that Unity3D serializing fields breaks null coalescing operator in Mono engine. I still don't know how, but maybe just due to changing
==
operator of seriazlized type??Anyway I hope it helps at least a little bit.