null合并运算符赋值给自

时间:2016-05-31 11:25:46

标签: c# serialization unity3d null null-coalescing-operator

我目前在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-coalessing运算符将null设置为specifiedUISound,即使它为空并且audioUIManager的声音不是即可。另外,如果我使用三元运算符来检查null,我可以使用它:

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

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

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

2 个答案:

答案 0 :(得分:10)

你正在遇到Unity的custom equality operator

  

当MonoBehaviour有字段时,仅在编辑器中,我们不会将这些字段设置为“真正的空”,而是设置为“假空”对象。我们的自定义==运算符能够检查某些东西是否是这些假的空对象之一,并且相应地表现。虽然这是一个奇特的设置,它允许我们将信息存储在假的null对象中,当您在其上调用方法时,或者当您向对象请求属性时,它会为您提供更多上下文信息。如果没有这个技巧,你只会得到一个NullReferenceException,一个堆栈跟踪,但是你不知道哪个GameObject有MonoBehaviour,那个字段是null。

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

specifiedUISound是否等于null?这取决于你的要求。 C#有多个“平等”概念,包括data equality and reference equality

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

其他人会说他们不平等:??Object.ReferenceEquals

此行为仅在编辑器中发生。在独立版本中运行时,任何null值都只是null

答案 1 :(得分:2)

对于你的问题和非常有趣的例子,它并不是真正完整的答案,但我运行了一些测试,看起来问题出现在SerializeField属性中。

当我运行此操作时(someObj从检查员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));
    }

我有这个版画:

enter image description here

然而,摆脱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));
    }

给出:

enter image description here

重新说明:

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

无论如何,我希望它至少有一点帮助。