3

I have attached a script to a Unity game object. The script contains various public properties, including some of my own classes. Like in the following simplified code, where the TestMonoBehaviorClass is attached to a game object and the TestClass' TestString is shown in the inspector.

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";
    }
}

I would expect that the constructor of the TestClass (Edit: NOT the one derived from MonoBehavior) is called once, when I attach the script to the game object. But it is called four times if I run the program in the Unity editor and then stop the program. Seven times if I have the script attached to two game objects. At least I see the output of the Debug.Log in the console that many times.

Still, if I change the content of the TestString property in the editor, the content I enter manually is NOT overwritten!

Why is the constructor called that often? When is it called in Unity's execution order (Unity's execution order of event functions)? Can I kind of ignore the call, or do I have to add special handling into my constructor? So far I didn't see any actual problem or side-effect.

Edit: It seems that only constructors without parameters are called. If I only have constructors with parameters, then none is called.

Programmer
  • 121,791
  • 22
  • 236
  • 328
Azarias
  • 43
  • 6

2 Answers2

8

[System.Serializable] is why the constructor is being called multiple times. Just ignore it unless there is a bug that results because of that, then ask question about that specific bug for a work-around solution. If you remove [System.Serializable], Unity won't serialize the TestClass class and the constructor will be called once instead of multiple times.

Edit: It seems that only constructors without parameters are called. If I only have constructors with parameters, then none is called.

With [System.Serializable], Unity serialization will call the default constructor multiple times during serialization and desalination because it needs to recreate the Object when it is de-serialized. The constructor function is used to do this. See this post for other similar multiple constructor call issue in Unity.

Edit:

If you want to do stuff before or after the serialization is done, you can implement ISerializationCallbackReceiver interface and use the OnBeforeSerialize() or OnAfterDeserialize() function to do this respectively.

For example:

[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);
    }
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Your edit is as well very helpful. So far I only used the `[System.Serializable]` attribute to make properties visible in the Unity inspector. But I will probably use it for serialization of some objects into files. Thank you for your reply, as well for the cleanup of the question title! – Azarias Sep 26 '17 at 13:27
-1

You should not use constructors in Unity use the Awake function instead to assign values, if not you can create your own setter function to set the values.

Check this: http://answers.unity3d.com/questions/862032/c-constructor-in-monobehaviour.html

Chopi
  • 1,123
  • 1
  • 12
  • 23
  • Yes, absolutely for classes derived from MonoBehavior Awake and Start should be used. I have classes, which are NOT derived from MonoBehavior, but provide certain data structures/ behavior etc. which I use. For these I do have constructors. – Azarias Sep 26 '17 at 11:16
  • Yep I saw late that you have an non-MonoBheaviour script. http://answers.unity3d.com/questions/232531/class-constructor.html Does this help you? In the Awake of TestMonoBehaviorClass try to create a instance of your class. – Chopi Sep 26 '17 at 11:20