1

Let's say we have a MonoBehavior class that has a custom variable declared as follows:

using UnityEngine;

public class TestScript : MonoBehaviour
{
    public static SimpleClass ClassInstance = new SimpleClass(10f);
}

"SimpleClass" is a simple C# class with a variable and a constructor:

public class SimpleClass
{
    public float Value;

    public SimpleClass(float value)
    {
        // When will this code execute?
        Value = value;
    }
}

I've spend whole evening trying to get when Unity actually calls constructor code in its execution order (if it even related to it).

When you create a struct it's declared instantly (as visible in editor), but this is not the case when class instance is produced. (unless it's List or Array)

In this example "ClassInstance" gets created even if MonoBehavior is disabled or put on inactive GameObject - so it's not "Start" or "Awake" loop too.

sweatyDev
  • 63
  • 8
  • 1
    Likely before Start and Awake of the MonoBehaviour since it could be needed in those. So that'd be the MB constructor which is not visible to users. – Everts Apr 16 '23 at 18:27

1 Answers1

1

You're correct that it has nothing to do with execution order or unity event funtions, or even unity at all! It's a feature of c#.

As it's a static field then it's initialised at some point. This answer goes into more detail but it's effectively indeterminate when exactly this will be initalised, except it will be initialised before you need to use it.

If the field is not static then it's simply a field initialiser (link) and is executed as the object is initialised.

(Tehnically it happens just before the constructor is called, but Unity doesn't give us access to the constructor so you can think of it being called as soon as the object is created. Worth noting is it will be called as the object is cread in any context, including in the editor, if such things are relavent.)

We can demonstrate this by simply debug logging in a class' constructor:

public class MonoBehaviourClass : MonoBehaviour
{

    private NormalClass c = new NormalClass();

    private void Awake()
    {
        Debug.Log("Awake!");
    }

}

public class NormalClass
{
    public NormalClass()
    {
        Debug.Log("Class Created!");
    }
}

This results in logging "Class Created" when the adding this component to an object, even in edit mode, and entering play mode will log this before "Awake" logs.

It is worth noting that this behaviour can be unpredictable in the Editor, as unity will serialise and deserialise your object quite often, resulting in the initiliser being called at sometimes unexpected times. For instance, the NormalClass constructor seems to be called whenever a recompilation is triggered, and seems to be called twice when entering a play mode scene containing this component. For this reason, it's best to avoid constructors with and side effects that will be initilised in MonoBehaviours.

Jay
  • 2,553
  • 3
  • 17
  • 37