Version: Unity 6.0 (6000.0)
语言 : 中文
脚本序列化
自定义序列化

序列化规则

Unity 中的序列化器专门设计为在运行时高效运行。因此,Unity 中的序列化与其他编程环境中的序列化具有不同的行为。Unity 中的序列化程序直接作用于 C# 类的字段而不是属性,因此 Unity 仅在字段满足特定条件时才对其进行序列化。以下部分概述了如何在 Unity 中使用字段序列化。

要使用字段序列化,必须确保字段:

  • public,或具有 SerializeField 属性
    • 注意:在某些情况下,private 字段被序列化,请参阅热重载
  • static
  • const
  • readonly
  • 具有可序列化的字段类型:
    • 原始数据类型(`int`、`float`、`double`、`bool`、`string` 等)
    • 枚举类型(32 位或更小)
    • 固定大小的缓冲区
    • Unity 内置类型,例如 Vector2、Vector3、Rect、Matrix4x4、Color、AnimationCurve
    • 具有 Serializable 属性的自定义结构
    • 对从 UnityEngine.Object 派生的对象的引用
    • 具有 Serializable 属性的自定义类。(请参阅自定义类的序列化)。
    • 上述字段类型的数组
    • 上述字段类型的 List<T>

注意:Unity 不支持多级类型(多维数组、交错数组、词典和嵌套容器类型)的序列化。如果要序列化这些类型,可使用两种方法:

自定义类的序列化

Unity 要序列化自定义类,必须确保该类:

将派生自 UnityEngine.Object 的类的实例分配给字段并且 Unity 保存该字段时,Unity 会将该字段序列化为对该实例的引用。Unity 会单独序列化实例本身,因此在为实例分配多个字段时不会重复。但对于不派生自 UnityEngine.Object 的自定义类,Unity 会直接将实例的状态包含在引用这些类的 MonoBehaviour 或 ScriptableObject 的序列化数据中。有两种方法可以做到这一点:内联[SerializeReference]

  • 内联序列化:默认情况下,如果未在引用了类的字段上指定 [SerializeReference],Unity 会按值将自定义类内联序列化。如果在多个不同的字段中存储对自定义类的实例的引用,则在序列化时它们将成为单独的对象。然后,当 Unity 反序列化这些字段时,它们将包含具有相同数据的不同对象。
  • [SerializeReference] 序列化:如果确实指定了 [SerializeReference],Unity 会将对象设定为托管引用。主机对象仍然将对象直接存储在其序列化数据中,但在一个专门的注册表部分。

[SerializeReference] 会增加一些开销,但支持以下情况:

  • 字段可为 null。内联序列化不能表示 null,而是用具有未分配字段的内联对象替换 null。
  • 对同一对象的多次引用。如果在多个不同的字段中存储对自定义类的实例的引用而没有使用 [SerializeReference],则在序列化时它们将成为单独的对象。
  • 图形和循环数据(例如,具有可回传到自身的引用的对象)。内联类序列化不支持 null 或共享引用,因此数据中的任何循环都可能导致意外结果,例如奇怪的 Inspector 行为、控制台错误或无限循环。
  • 多态。如果创建一个派生自父类的类,并将其分配给一个使用父类作为其类型的字段而没有使用 [SerializeReference],则 Unity 只会序列化属于父类的字段。Unity 反序列化类实例时,它会实例化父类而不是派生类。
  • 当数据结构需要一个稳定的标识符来指向特定对象,而不通过硬编码对象的数组位置或搜索整个数组时。请参阅 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] 属性。

其他资源

脚本序列化
自定义序列化