序列化规则
Conditions that determine whether fields in your scripts are serialized.
阅读时间6 分钟最后更新于 1 个月前
Unity 中的序列化器专门设计为在运行时高效运行。因此,Unity 中的序列化与其他编程环境中的序列化具有不同的行为。Unity 中的序列化程序直接作用于 C# 类的字段而不是属性,因此 Unity 仅在字段满足特定条件时才对其进行序列化。以下部分概述了如何在 Unity 中使用字段序列化。
要使用字段序列化,必须确保字段:
-
是,或具有 SerializeField 属性
public- 注意:在某些情况下,字段被序列化,请参阅热重载
private
- 注意:在某些情况下,
-
非
static -
非
const -
非
readonly -
具有可序列化的字段类型:
- 原始数据类型(、
int、float、double、bool等)string - 枚举类型(32 位或更小)
- 固定大小的缓冲区
- Unity 内置类型,例如 Vector2、Vector3、Rect、Matrix4x4、Color、AnimationCurve
- 具有 Serializable 属性的自定义结构
- 对从 UnityEngine.Object 派生的对象的引用
- 具有 Serializable 属性的自定义类。(请参阅自定义类的序列化)。
- 上述字段类型的数组
- 上述字段类型的
List<T>
- 原始数据类型(
注意:Unity 不支持多级类型(多维数组、交错数组、词典和嵌套容器类型)的序列化。如果要序列化这些类型,可使用两种方法:
- 将嵌套类型放在类或结构中
- 通过实现 ISerializationCallbackReceiver,使用序列化回调来执行自定义序列化。
自定义类的序列化
Unity 要序列化自定义类,必须确保该类:
- 具有 Serializable 属性
- 非静态。
将派生自 的类的实例分配给字段并且 Unity 保存该字段时,Unity 会将该字段序列化为对该实例的引用。Unity 会单独序列化实例本身,因此在为实例分配多个字段时不会重复。但对于不派生自 的自定义类,Unity 会直接将实例的状态包含在引用这些类的 MonoBehaviour 或 ScriptableObject 的序列化数据中。有两种方法可以做到这一点:内联和****。
UnityEngine.ObjectUnityEngine.Object[SerializeReference]- 内联序列化:默认情况下,如果未在引用了类的字段上指定 ,Unity 会按值将自定义类内联序列化。如果在多个不同的字段中存储对自定义类的实例的引用,则在序列化时它们将成为单独的对象。然后,当 Unity 反序列化这些字段时,它们将包含具有相同数据的不同对象。
[SerializeReference] - 序列化:如果确实指定了
[SerializeReference],Unity 会将对象设定为托管引用。主机对象仍然将对象直接存储在其序列化数据中,但在一个专门的注册表部分。[SerializeReference]
[SerializeReference]- 字段可为 null。内联序列化不能表示 null,而是用具有未分配字段的内联对象替换 null。
- 对同一对象的多次引用。如果在多个不同的字段中存储对自定义类的实例的引用而没有使用 ,则在序列化时它们将成为单独的对象。
[SerializeReference] - 图形和循环数据(例如,具有可回传到自身的引用的对象)。内联类序列化不支持 null 或共享引用,因此数据中的任何循环都可能导致意外结果,例如奇怪的 Inspector 行为、控制台错误或无限循环。
- 多态。如果创建一个派生自父类的类,并将其分配给一个使用父类作为其类型的字段而没有使用 ,则 Unity 只会序列化属于父类的字段。Unity 反序列化类实例时,它会实例化父类而不是派生类。
[SerializeReference] - 当数据结构需要一个稳定的标识符来指向特定对象,而不通过硬编码对象的数组位置或搜索整个数组时。请参阅 Serialization.ManagedReferenceUtility.SetManagedReferenceIdForObject。
注意:内联序列化更高效,除非特别需要 支持的功能之一,否则应该使用内联序列化。有关如何使用 的完整详细信息,请参阅 SerializeReference 文档。
[SerializeReference][SerializeReference]属性的序列化
Unity 通常不会序列化属性,但以下情况除外:
- 如果属性具有显式后备字段,Unity 将根据常规序列化规则对其进行序列化。例如:
public int MyInt{get => m_backing;private set => m_backing = value;}[SerializeField] private int m_backing;
- Unity 仅在热重载期间序列化具有自动生成字段的属性。
public int MyInt { get; set; }
如果不希望 Unity 使用自动生成的字段序列化属性,请使用 属性。
[field: NonSerialized]