写过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时也会调用构造函数,如下图,你会发现私有的构造函数被多次调用。
一开始我也是百思不得其解,甚至怀疑以前自已写的C#程序写错了,也没仔细去分析,只是写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;
}
}