Unity 6.3
0 онлайн 57 гостей 3 в системе
Вход
Программирование в Unity Шаг 93 из 210

Правила сериализации

Unity использует собственную систему серийного кодирования, которая специально разработана для эффективной работы во время выполнения. Из-за этого серийное кодирование в Unity ведет себя иначе, чем серийное кодирование в других средах программирования.

Unity поддерживает стандарт .NET/C# [Serializable] и [NonSerialized] атрибуты, но их поведение в Unity зависит и от дополнительных особенностей самой Unity. Unity не сериализует автоматически класс, помеченный [Serializable] если он не соответствует правилам серийного номера Unity, изложенным в следующих разделах.

Unity автоматически сериализует встроенные типы Unity, которые наследуются от UnityEngine.Object, так что вам нужно применять [Serializable] только к пользовательским классам или структурам, используемым в качестве полей в этих объектах Unity. Атрибут [NonSerialized] используется в Unity как в стандартном C# для исключения полей из сериализации. Однако в контексте Unity это также препятствует Inspector сериализовать или отображать это поле. Unity имеет свой собственный атрибут, [HideInInspector], который скрывает поле в Inspector без предотвращения сериализации.

Важно: Для серийизации структур или пользовательских классов, не полученных из UnityEngine.Object, вы должны аннотировать их с помощью [Serializable]. Следует отметить, что [Serializable] атрибут не наследуется подклассами автоматически, поэтому его нужно применять ко всем классам иерархии. При неправильном использовании Unity Editor выдаёт предупреждения. Подробнее см. Сериализация пользовательских классов.

Правила сериализации полевых данных

Сериализаторы в Unity работать непосредственно на полей вашего C# классы, а не их свойства, так что Unity В следующем разделе описывается, как использовать сериализацию полей в таблицах, в которых используется Unity.

Для использования серийного номера поля необходимо убедиться, что поле:

  • Ис public, или имеет [SerializeField] атрибут
  • Не static
  • Не const
  • Не readonly
  • Имеет тип поля, который может быть серийным:
    • Примитивные типы данных (int, float, double, bool, string и т.д.).
    • Типы Enum (32 бита или меньше).
    • Буферы фиксированного размера.
    • Unity встроенные типы, например, Vector2, Vector3, Rect, Matrix4x4, Color, AnimationCurve.
    • Пользовательские структуры с атрибутом [Serializable].
    • Ссылки на объекты, полученные из UnityEngine.Object.
    • Пользовательские классы с атрибутом [Serializable]. (См. Сериализация пользовательских классов).
    • Массив или List<T> одного из ранее перечисленных типов полей. При серийнизации по значению по умолчанию, если один элемент появляется в списке или массиве дважды, то серийнизированная версия коллекции будет иметь две копии этого элемента, а не одну копию, которая появляется дважды. При серийнизации коллекции классов по ссылке, сохраняются множественные ссылки на один и тот же объект. Дополнительную информацию см. в документации [SerializeReference] API.

Примечание: Unity не поддерживает сериализацию многоуровневых типов (многомерные массивы, зубчатые массивы, словари и вложенные типы контейнеров). Если вы хотите сериализировать их, у вас есть два варианта:

Сериализация пользовательских классов

Чтобы Unity сериализовала пользовательский класс, он должен удовлетворять следующим условиям:

  • Имеет атрибут [Serializable].
  • Не является статическим.

При назначении экземпляра UnityEngine.Object-производного класса полю, и Unity сохраняет это поле, Unity сериализует поле как ссылку на этот экземпляр. Сам экземпляр Unity сериализует отдельно, поэтому он не дублируется, когда на него ссылается несколько полей. Но для пользовательских классов, не наследующих UnityEngine.Object, Unity включает состояние экземпляра прямо в сериализованные данные того MonoBehaviour или ScriptableObject, который на него ссылается. Это может произойти двумя способами: встроенный и [SerializeReference].

  • Встроенная сериализация: По умолчанию, Unity сериализирует пользовательские классы в строке по значению, когда вы не указываете [SerializeReference] к полю, ссылающемуся на класс. Это значит, что если вы храните ссылку на экземпляр пользовательского класса в нескольких разных полях, при сериализации они станут отдельными объектами. Затем, при десериализации, в этих полях окажутся разные объекты с одинаковыми данными.
  • [SerializeReference] сериализация: Если вы указываете [SerializeReference], Unity устанавливает объект как управляемую ссылку. Хост-объект по-прежнему хранит объекты непосредственно в своих серийных данных, но в специальном разделе реестра.

[SerializeReference] добавляет некоторые накладные расходы, но поддерживает следующие случаи:

  • Поля могут быть нулевыми. Встроенная серийнизация не может представлять нулевое значение, вместо этого она заменяет нулевое значение встроенным объектом, имеющим неназначенные поля.
  • Несколько ссылок на один и тот же объект. Если вы храните ссылку на экземпляр пользовательского класса в нескольких разных полях, не используя [SerializeReference], а затем они становятся отдельными объектами при серийном кодировании.
  • Графы и циклические данные (например, объект, ссылающийся сам на себя). Встроенная сериализация классов не поддерживает null и разделяемые ссылки, поэтому любой цикл в данных может дать неожиданный результат: странное поведение инспектора, ошибки в консоли или бесконечные циклы.
  • Полиморфизм. Если вы создаёте класс, производный от родительского, и присваиваете его полю, тип которого — родительский класс, без [SerializeReference] Unity сериализует только поля, принадлежащие родительскому классу. При десериализации экземпляра Unity создаёт родительский класс, а не производный.
  • Когда структура данных требует стабильного идентификатора для указания на конкретный объект без жесткого кодирования позиции массива объекта или поиска по всему массиву. См. Serialization.ManagedReferenceUtility.SetManagedReferenceIdForObject.

Примечание: Встроенная серийнизация более эффективна, и вы должны использовать ее, если вам не нужна какая-либо из функций, поддерживаемых [SerializeReference]. Полные сведения об использовании [SerializeReference]см. в документации по ,SerializeReferenceи.

Когда вы используете [SerializeReference], Unity строго не применяет [Serializable], но выводит предупреждение в Console, если класс не помечен [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;}

Дополнительные ресурсы