2016-05-31 23 views
4

我目前在Unity中設置了兩個腳本來處理某些UI音頻。一個是經理,另一個是爲特定的用戶界面元素播放聲音。什麼,我有一個簡化的版本是這樣的:null合併操作員分配給自己

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管理器中的通用聲音。這節省了我爲數百萬個需要相同聲音的按鈕分配相同的聲音,但是如果我願意的話,可以給我一個按鈕的特定聲音。

然而,包括空coalessing算asigning nullspecifiedUISound即使爲null和audioUIManager的聲音不。另外,我能得到這個工作,如果我使用三元運算檢查null像這樣:

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

我誤解了空合併運算符?爲什麼會發生?

編輯: Jerry Switalski指出,這隻發生在specifiedUISound序列化時。 (如果它是public或者它具有[SerializeField]屬性)。任何人都可以點亮這裏發生的事情嗎?

+0

s = s ?? 「測試」;在這裏工作正常 – Laurijssen

+2

所以你說'foo = foo? bar'不起作用,但是'foo = foo == null? bar:foo'呢? Unity沒有改變C#規則,所以它一定是你的代碼。你是否可能在創建[mcve]方面做得太過分,以至於你刪除了太多相關的代碼? AudioClip是什麼類型的,它是一個結構體還是一個類? – CodeCaster

+0

是的,我測試了這個例子,它重新創建了這個問題。如果你製作這兩個類並將它們添加到兩個不同的遊戲對象中,那麼它會重新創建它!如果我明顯不以這種方式使用它,它正常工作。 –

回答

7

您正在運行到統一的custom equality operator

當MonoBehaviour有田,在編輯器中唯一的,我們不設置這些字段爲「真空」,而是一個「假空」的對象。我們的自定義==操作符能夠檢查這些假空對象是否是其中的一個,並相應地執行操作。雖然這是一個奇特的設置,但它允許我們將信息存儲在假空對象中,當您調用其上的方法或向對象請求屬性時,可以爲您提供更多上下文信息。沒有這個技巧,你只會得到一個NullReferenceException,一個堆棧跟蹤,但你不知道哪個GameObject有MonoBehaviour的字段爲空。

雖然在編輯器中運行,統一替換您的序列化null與警戒值實際上不是null。這允許他們在某些情況下提供更多信息性的錯誤消息。

specifiedUISound等於null?這取決於你如何問。 C#有多個「平等」的概念,包括data equality and reference equality

一些檢查,會說這兩個值相等:==Object.Equals

其他人會說,他們是不相等的:??Object.ReferenceEquals

這種行爲只會出現在編輯器中。當在獨立版本中運行時,任何null值將只是null

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

所以reasuming:

我真的不知道問題的根源,但什麼是事實是,Unity3D序列化領域的單引擎打破了空合併運算符。我仍然不知道如何,但也許只是由於改變seriazlized類型的運算符== ??

無論如何,我希望它至少有一點幫助。

+0

非常有趣,很好找! –

+0

我希望它有幫助,實際上你也可以通過將nullObj作爲公共來重現它(Unity會自動地對這個字段進行serilize) - 那麼即使是null,給定的運算符也不會正常工作。 –

+0

真棒,超級有用。我會拭目以待,看看有沒有人知道爲什麼會發生這種情況,如果沒有,請接受! –

相關問題