问题引入

在 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 内部机制导致的"副作用",并不是用户代码的问题。