1. 程式人生 > >UNITY 單一模式的坑,別寫建構函式

UNITY 單一模式的坑,別寫建構函式

寫過C#程式碼的小夥伴,寫單例模式時,習慣如下寫法,用靜態屬性加私有建構函式,OK,一切看上去都不錯。

但是,下面的程式碼,在UNITY中卻怎麼也不好使,因為繼承自MonoBehaviour. 

public class UIManager : MonoBehaviour {

    private static UIManager _instance;
    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            { 
                _instance = new UIManager();
            }
            return _instance;
        }
    }

    private UIManager()
    { 
        print("呼叫建構函式");
    }
}

如果你把這段程式碼掛在Gameobject上執行,你會發現建構函式被呼叫很多次,即使你不掛在GameObject上,在其它指令碼中寫UIManager.Instance時也會呼叫建構函式,如下圖,你會發現私有的建構函式被多次呼叫。

一開始我也是百思不得其解,甚至懷疑以前自已寫錯了,以至於寫UNITY時所有的單例模式我都不繼承自MonoBehaviour.

直到後來,看到了官方解釋,終於明白了怎麼回事,如下:

Avoid using the constructor.  避免使用建構函式  Never initialize any values in the constructor. Instead use Awake or Start  for this purpose. Unity automatically invokes the constructor even when in edit  mode. This usually happens directly after compilation of a script, because the  constructor needs to be invoked in order to retrieve default values of a script.  Not only will the constructor be called at unforeseen times, it might also be  called for prefabs or inactive game objects.  不要在建構函式中初始化任何變數.要用Awake或Start函式來實現.即便是在編輯模式,Unity仍會自動呼叫建構函式.這通常是在一個指令碼編譯之後,因為需要呼叫指令碼的建構函式來取回指令碼的預設值.我們無法預計何時呼叫建構函式,它或許會被預置體或未啟用的遊戲物件所呼叫. In the case of eg. a singleton pattern using the constructor this can have  severe consequences and lead to seemingly random null reference exceptions.  單一模式使用建構函式可能會導致嚴重後果,會帶來類似隨機的空引數異常. 

So if you want to implement eg. a singleton pattern do not use the the  constructor, instead use Awake . Actually there is  no reason why you should ever have any code in a constructor for a class that  inherits from MonoBehaviour . 因此,如果你想實現單一模式不要用建構函式,要用Awake函式.事實上,你沒必要在繼承自MonoBehaviour的類的建構函式中寫任何程式碼.

因些我們在寫單例模式時千萬不能用建構函式。現在百度搜出來好多程式碼還有建構函式誤導初學者的。

最簡單的寫法只要用到AWAKE方法就好了,這也是官司方推薦做法

public class UIManager : MonoBehaviour {

    private static UIManager _instance;
    
    void Awake()
    {
        _instance = this;
    }
 
}