问题引入
在 Unity 中写了一个可序列化的自定义类 Data,并在 MonoBehaviour 中引用它,代码如下:
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Data
{
public int x = 4;
public void pri()
{
Debug.Log(" value is " + x.ToString());
}
public Data()
{
Debug.Log("Data()");
}
}
public class Library_NewBehaviourScript : MonoBehaviour
{
public Library_NewBehaviourScript()
{
Debug.Log("Library_NewBehaviourScript()");
}
public int x;
[SerializeField]
private int y;
private Data data;
void Start()
{
data.pri();
}
void Update()
{
}
}
现象
运行后控制台显示 Data 的构造函数被调用了 2 次,但是 data.pri() 却抛出空引用异常,提示 data 为空。
疑问
代码里并没有 new Data(),为什么构造器会被调用 2 次?既然构造器执行了,为什么 data 仍然是 null?
原因分析
原因在于 Unity Editor 内部做了远比我们写的这点代码要多的工作。Editor 会对带 [System.Serializable] 的类做额外的实例化处理,这就解释了为什么构造函数会被重复调用;而字段本身没有被真正赋值到运行时实例,所以 data 依然是空引用,这是正常的。
即使把字段改成 [SerializeField] private Data data = new Data();,构造函数同样会被调用 2 次,结论一致。
验证
在 Release 模式下得到了同样的验证结果,如下图所示:
结论
构造函数被调用 2 次,是 Unity Editor 内部机制导致的"副作用",并不是用户代码的问题。