【问题标题】:Why multiple constructor calls in a non MonoBehaviour serialized class?为什么在非 MonoBehaviour 序列化类中调用多个构造函数?
【发布时间】:2017-09-26 10:47:12
【问题描述】:

我已将脚本附加到 Unity 游戏对象。该脚本包含各种公共属性,包括我自己的一些类。就像下面的简化代码一样,TestMonoBehaviorClass 附加到游戏对象,TestClass'TestString 显示在检查器中。

public class TestMonoBehaviorClass : MonoBehaviour
{
    public TestClass Test;
}

[System.Serializable]
public class TestClass
{
    public string TestString;
    public TestClass ()
    {
        Debug.Log ("TestClass creator called.");
        this.TestString = "Reset String";
    }
}

我希望 TestClass 的构造函数(编辑:不是从 MonoBehavior 派生的构造函数)在我将脚本附加到游戏对象时被调用一次。但是如果我在 Unity 编辑器中运行程序然后停止程序,它会被调用四次。如果我将脚本附加到两个游戏对象,则七次。至少我在控制台中多次看到 Debug.Log 的输出。

不过,如果我在编辑器中更改TestString 属性的内容,我手动输入的内容不会被覆盖!

为什么经常调用构造函数? Unity 的执行顺序(Unity's execution order of event functions)何时调用它? 我可以忽略调用,还是必须在构造函数中添加特殊处理?到目前为止,我没有看到任何实际问题或副作用。

编辑: 似乎只调用了没有参数的构造函数。如果我只有带参数的构造函数,则不会调用任何构造函数。

【问题讨论】:

    标签: c# unity3d constructor execution inspector


    【解决方案1】:

    [System.Serializable] 是构造函数被多次调用的原因。只需忽略它,除非因此产生错误,然后询问有关该特定错误的问题以寻求解决方案。如果您删除 [System.Serializable],Unity 将不会序列化 TestClass 类,并且构造函数将被调用一次而不是多次。

    编辑:似乎只调用了没有参数的构造函数。 如果我只有带参数的构造函数,则不会调用任何构造函数。

    使用[System.Serializable],Unity序列化在序列化和淡化过程中会多次调用默认构造函数,因为反序列化时需要重新创建Object。构造函数用于执行此操作。有关 Unity 中其他类似的多构造函数调用问题,请参阅 this 帖子。

    编辑:

    如果你想在序列化完成之前或之后做一些事情,你可以实现ISerializationCallbackReceiver接口并分别使用OnBeforeSerialize()OnAfterDeserialize()函数来做这件事。

    例如:

    [System.Serializable]
    public class TestClass : ISerializationCallbackReceiver
    {
        public string TestString;
        public TestClass()
        {
            Thread thread = Thread.CurrentThread;
            Debug.Log("TestClass creator called: " + thread.ManagedThreadId);
    
            this.TestString = "Reset String";
        }
    
        public void OnAfterDeserialize()
        {
            Thread thread = Thread.CurrentThread;
            Debug.LogWarning("OnAfterDeserialize Thread ID: " + thread.ManagedThreadId);
        }
    
        public void OnBeforeSerialize()
        {
            Thread thread = Thread.CurrentThread;
            Debug.LogWarning("OnBeforeSerialize Thread ID: " + thread.ManagedThreadId);
        }
    }
    

    【讨论】:

    • 您的编辑也很有帮助。到目前为止,我只使用了[System.Serializable] 属性来使属性在 Unity 检查器中可见。但我可能会用它来将一些对象序列化为文件。感谢您的回复,以及对问题标题的清理!
    【解决方案2】:

    你不应该在 Unity 中使用构造函数,而是使用 Awake 函数来分配值,否则你可以创建自己的 setter 函数来设置值。

    检查这个:http://answers.unity3d.com/questions/862032/c-constructor-in-monobehaviour.html

    【讨论】:

    • 是的,绝对应该使用从 MonoBehavior Awake 和 Start 派生的类。我有类,它们不是从 MonoBehavior 派生的,而是提供我使用的某些数据结构/行为等。对于这些,我确实有构造函数。
    • 是的,我很晚才看到你有一个非 MonoBheaviour 脚本。 answers.unity3d.com/questions/232531/class-constructor.html 这对你有帮助吗?在 TestMonoBehaviorClass 的唤醒中尝试创建您的类的实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    • 2021-04-01
    • 2013-01-28
    • 1970-01-01
    • 2016-03-26
    • 2021-10-19
    • 1970-01-01
    相关资源
    最近更新 更多