英文:
When does Unity execute the constructor code of a simple class if "new" instance was called upon variable declaration?
问题
以下是您要翻译的内容:
假设我们有一个MonoBehavior类,其中一个自定义变量声明如下:
using UnityEngine;
public class TestScript : MonoBehaviour
{
public static SimpleClass ClassInstance = new SimpleClass(10f);
}
"SimpleClass" 是一个简单的C#类,具有一个变量和一个构造函数:
public class SimpleClass
{
public float Value;
public SimpleClass(float value)
{
// 这段代码何时执行?
Value = value;
}
}
我整个晚上都在尝试弄清楚Unity何时实际调用构造函数代码的问题执行顺序(如果它与之相关的话)。
当你创建一个结构体时,它会立即声明(在编辑器中可见),但在生成类实例时情况并非如此(除非是List或Array)。
在这个示例中,即使MonoBehavior被禁用或放在非活动的GameObject上,"ClassInstance"也会被创建,因此它与"Start"或"Awake"循环无关。
英文:
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.
答案1
得分: 1
你说得对,这与执行顺序或统一事件函数无关,甚至与Unity毫无关系!这是C#的一个特性。
因为它是一个静态字段,所以它会在某个时刻被初始化。这个答案提供了更多详细信息,但确切的初始化时间实际上是不确定的,除非在你需要使用它之前会被初始化。
如果字段不是静态的,那么它只是一个字段初始化器(链接),会在对象初始化时执行。
(技术上来说,它发生在构造函数被调用之前,但Unity不允许我们访问构造函数,所以你可以将其视为在对象创建时立即调用。值得注意的是,它将在对象在任何上下文中被创建时调用,包括在编辑器中,如果这些情况相关的话。)
我们可以通过在类的构造函数中简单地进行调试日志记录来证明这一点:
public class MonoBehaviourClass : MonoBehaviour
{
private NormalClass c = new NormalClass();
private void Awake()
{
Debug.Log("Awake!");
}
}
public class NormalClass
{
public NormalClass()
{
Debug.Log("Class Created!");
}
}
这将导致在将此组件添加到对象时记录"Class Created",即使在编辑模式下,进入播放模式也会在"Awake"之前记录。
值得注意的是,在编辑器中,这种行为可能是不可预测的,因为Unity会经常对你的对象进行序列化和反序列化,导致初始化器在某些时候被调用的时机可能会出人意料。例如,NormalClass
构造函数似乎在触发重新编译时会被调用,并且在进入包含此组件的播放模式场景时似乎会被调用两次。因此,最好避免在MonoBehaviours中具有会在初始化时产生副作用的构造函数。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论