Version: 6000.3
语言: 中文
脚本序列化
自定义序列化

序列化规则

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-derived 类添加到字段,并且 Unity 保存该字段,Unity 将该字段序列化为对该实例的引用。Unity 独立序列化实例本身,因此当为实例分配多个字段时,它不会重复。但是对于不派生自UnityEngine.Object,Unity 将实例的状态直接包含在引用它们的 MonoBehaviour 或 ScriptableObject 的序列化数据中。有两种方式可以发生这种情况:内联和通过[SerializeReference].

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

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

  • 字段可以为 null。内联序列化不能表示 null,而是将 null 替换为具有未分配字段的内联对象。
  • 对同一对象的多个引用。如果将对自定义类实例的引用存储在多个不同的字段中,而不使用[SerializeReference],则它们在序列化时成为单独的对象。
  • 图形和循环数据(例如,具有对自身的引用的对象)。内联类序列化不支持 null 或共享引用,因此数据中的任何循环都可能导致意外结果,例如检查器一个 Unity 窗口,显示有关当前选定游戏对象、资产或项目设置的信息,允许您检查和编辑值。更多信息
    请参阅术语表
    行为、控制台错误或无限循环。
  • 多态性。如果您创建派生自父类的类,并将其分配给使用父类作为其类型的字段,则无需[SerializeReference]Unity 仅序列化属于父类的字段。当 Unity 反序列化类实例时,它会实例化父类而不是派生类。
  • 当数据结构需要稳定的标识符来指向特定对象时,而无需对对象的数组位置进行硬编码或搜索整个数组。请参阅 Serialization.ManagedReferenceUtility.SetManagedReferenceIdForObject

注意:内联序列化效率更高,除非您特别需要以下功能之一,否则您应该使用它[SerializeReference]支持。有关如何使用的完整详细信息[SerializeReference],请参阅 SerializeReference 文档。

当您使用[SerializeReference],Unity 并不严格执行[Serializable],但如果未标记类,则在控制台中显示警告[Serializable].可以使用 MakeSerializable 属性抑制此警告。

属性序列化

Unity 不会序列化属性。但是,如果属性由字段支持,则可以序列化该字段。

  • 如果属性具有显式支持字段,Unity 会根据常规序列化规则对其进行序列化。例如:
public int MyInt
{
get => m_backing;
private set => m_backing = value;
}
[SerializeField] private int m_backing;
  • 如果属性是自动属性,则编译器会隐式为其生成专用支持字段,并且常规序列化规则适用于此支持字段。您可以使用field:属性的前缀。例如:
// Serialize the implicit backing field behind this property
[field: SerializeField]
public int MyInt { get; set; }

// Serialize the implicit backing field behind this property as a reference instead of inline
[field: SerializeReference]
public MyType MyReferenceToType { get; set;}

// Do not serialize the backing field for this property even when hot-reloading
[field: NonSerialized]
public bool NeverSerializedProperty { get; set;}

其他资源

脚本序列化
自定义序列化