空合并运算符赋值给自己

null coalescing operator assignment to self

我目前在 Unity 中设置了两个脚本来处理一些 UI 音频。一个是管理器,另一个是为特定 UI 元素播放声音。我所拥有的简化版本是这样的:

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);
    }
}

我在这里想要实现的是让 specifiedUISound 字段使用在检查器中分配给它的声音。如果没有指定声音,则使用来自 UI 管理器的通用声音。这节省了我将相同的声音分配给数百万个需要相同声音的按钮,但如果我愿意,我可以选择为一个按钮提供特定的声音。

然而,空合并运算符正在将 null 分配给 specifiedUISound,即使 它为空且 audioUIManager的声音不是。另外,如果我像这样使用三元运算符检查 null,我可以让它工作:

specifiedUISound = specifiedUIsound == null ? audioUIManager.genericUISound : specifiedUISound;

我是否误解了空合并运算符?为什么会这样?

编辑: Jerry Switalski 指出,这仅在 specifiedUISound 被序列化时发生。 (如果它是 public 或者它具有 [SerializeField] 属性)。任何人都可以阐明这里发生的事情吗?

这不是你问题的完整答案和非常有趣的例子,但我 运行 测试了几次,看起来问题出在 SerializeField 属性中。

当我 运行 这个(someObj 是从 inspector nullObj 分配的,留空):

    public AudioClip someObj;

    [SerializeField]
    private AudioClip nullObj;

    void Start () 
    {
        Debug.Log("nullObj == null : " + (nullObj == null));
        Debug.Log("someObj == null : " + (someObj == null));

        nullObj = nullObj ?? someObj;

        Debug.Log ("nullObj == null : " + (nullObj == null));
    }

我有这张照片:

但是去掉 SerializeField 属性后,事情就会按预期进行:

    public AudioClip someObj;

    private AudioClip nullObj;

    void Start () 
    {
        Debug.Log("nullObj == null : " + (nullObj == null));
        Debug.Log("someObj == null : " + (someObj == null));

        nullObj = nullObj ?? someObj;

        Debug.Log ("nullObj == null : " + (nullObj == null));
    }

给出:

所以重新开始:

我真的不知道问题的根源,但事实是 Unity3D 序列化字段破坏了 Mono 引擎中的空合并运算符。我仍然不知道如何,但可能只是由于更改 == 序列化类型的运算符??

无论如何,我希望它至少能有所帮助。

您 运行 正在使用 Unity custom equality operator:

When a MonoBehaviour has fields, in the editor only, we do not set those fields to “real null”, but to a “fake null” object. Our custom == operator is able to check if something is one of these fake null objects, and behaves accordingly. While this is an exotic setup, it allows us to store information in the fake null object that gives you more contextual information when you invoke a method on it, or when you ask the object for a property. Without this trick, you would only get a NullReferenceException, a stack trace, but you would have no idea which GameObject had the MonoBehaviour that had the field that was null.

在编辑器中 运行 时,Unity 会将您的序列化 null 替换为实际上不是 null 的标记值。这允许他们在某些情况下提供更多信息性错误消息。

specifiedUISound等于null吗?那要看你怎么问了。 C# 有多个 "equality" 的概念,包括 data equality and reference equality.

有些检查会说值相等:==Object.Equals

别人会说不相等:??Object.ReferenceEquals

此行为只会发生在编辑器中。当 运行 在独立构建中时,任何 null 值将只是 null.