Как Unity использует сериализацию
Сохранение и загрузка
Unity использует сериализацию для загрузки и сохранения сцены, Активы, и AssetBundles в память вашего устройства и из нее. Это включает данные, сохраненные в вашем собственном сценарии API объекты, такие как MonoBehaviour компоненты и ScriptableObjects.
Многие функции Unity Editor построены на основе основной системы серийного кодирования. Две вещи, которые следует особо учитывать при серийном кодировании, это окно Inspectorи перезагрузка в горячем режиме.
Окно Inspector
Окно Inspector показывает значение серийных полей проверяемых объектов. Когда вы изменяете значение в Inspector, Inspector обновляет серийные данные и вызывает десерриализацию, которая обновляет проверяемый объект.
То же самое относится как к встроенным объектам Unity, так и к объектам скриптов, таким как классы, производные от MonoBehaviour.
Unity не вызывает никаких C# геттеров и сеттеров свойств, когда вы просматриваете или изменяете значения в окне Inspector. Вместо этого Unity напрямую получает доступ к серийному базовому полю.
Горячая перезагрузка
Горячая перезагрузка скриптового кода выполняется как часть обновления базы данных ассетов. Она относится к процессу перезагрузки и применения изменений в коде непосредственно во время работы Редактора, без необходимости его перезапуска. Дополнительные сведения см. в Обновление базы данных активов и Горячая перезагрузка.
Примечание: горячая перезагрузка — особый случай сериализации. В отличие от остальных случаев, при перезагрузке Unity по умолчанию сериализует и закрытые поля, даже если у них нет [SerializeField] атрибут.
Когда Unity перезагружает скрипты:
- Unity сериализирует и хранит все переменные во всех загруженных скриптах.
- Unity восстанавливает их в исходные значения до сериализации:
- Unity восстанавливает все переменные включая приватные переменные - которые отвечают требованиям для сериализации, даже если переменная не имеет
[SerializeField]атрибут. - Unity никогда не восстанавливает статические переменные, поэтому не используйте их для состояний, которые должны пережить перезагрузку скрипта: при перезагрузке они будут отброшены.
- Unity восстанавливает все переменные включая приватные переменные - которые отвечают требованиям для сериализации, даже если переменная не имеет
Предотвращение серийного номера и восстановления
Иногда нужно помешать Unity восстанавливать закрытые переменные — например, если после перезагрузки скриптов ссылка должна быть равна null. В этом случае используйте [NonSerialized] атрибут.
Поведение восстановления в Unity распространяется и на закрытые поля-хранилища, в которых хранится значение автоматически реализованные свойства в C#. Например, рассмотрим следующее автоматически реализованное свойство:
public string MyProperty { get; set; }
В этом случае C# добавляет в класс невидимое закрытое поле для хранения фактического значения MyProperty. Unity будет сериализировать и восстанавливать это значение во время горячей перезагрузки. [field: NonSerialized] на свойство.
В следующем примере показано использование атрибутов [NonSerialized] и [field: NonSerialized] для предотвращения сериализации и восстановления регулярных полей и подкрепляющего поля соответственно:
class Test
{
// p will not be shown in the Inspector or serialized
[System.NonSerialized]
public int p = 5;
// neverSerializeMe will never be serialized, even during an hot reload.
[System.NonSerialized]
private int neverSerializeMe;
// The backing field for NeverSerializedProperty property will never be serialized,
// even during a hot reload
[field: System.NonSerialized]
public int NeverSerializedProperty { get; set; }
}
Префабы
Префаб представляет собой сериализованные данные одного или нескольких GameObject или компонентов. Экземпляр префаба содержит ссылку на исходный префаб и список внесённых изменений. Эти изменения указывают Unity, как получить конкретный экземпляр префаба из исходного префаба.
Экземпляр префаб существует только во время редактирования проекта в Unity Editor. Unity Editor инстанционирует GameObject из двух наборов данных сериализации: источник префаб и модификации экземпляра префаб.
Инстанционирование
Когда вы вызываете Instantiate на что-либо, что существует в сцене, например, префаб или GameObject:
- Unity сериализирует его. Это происходит как во время выполнения, так и в Редакторе. Unity может сериализировать все, что происходит от
UnityEngine.Object. - Unity создает новый GameObject и десериализует данные в новом GameObject.
- Unity запускает тот же код серийного номера в другом варианте, чтобы сообщить, какие другие
UnityEngine.ObjectsОн проверяет все ссылкиUnityEngine.Objectsчтобы определить, входят ли они в данные, которые Unity создаёт заново. Если ссылка указывает на что-то внешнее, например на текстуру, Unity оставляет её как есть. Если ссылка указывает на что-то внутреннее, например на дочерний GameObject, Unity перенаправляет её на соответствующую копию.
Выгрузка неиспользуемого имущества
EditorUtility.UnloadUnusedAssetsImmediate является собственным сборщиком мусора Unity и имеет другое назначение, чем стандартный сборщик мусора C#. Он запускается после загрузки сцены и проверяет объекты (такие как Тексты), на которые она больше не ссылается, и безопасно выгружает их. Собственный сборщик мусора Unity запускает сериализатор в варианте, в котором объекты сообщают все ссылки на внешний UnityEngine.Objects. Таким образом Тексты, используемые одной сценой, сборщик мусора выгружает в следующей.
Различия между редактором и сериализацией времени выполнения
Большая часть сериализации происходит в Редакторе, в то время как десериялизация является фокусом во время выполнения. Unity сериализует некоторые функции только в Редакторе, в то время как она может сериализировать другие функции как в Редакторе, так и во время выполнения:
| Особенности | Редактор | Среда выполнения |
|---|---|---|
| Активы в двоичном формате | Поддержка чтения/записи | Читать поддерживается |
| Активы в YAML формат | Поддержка чтения/записи | Не поддерживается |
| Сохранение сцен, префабы и других активов | Поддерживается, если не в режиме воспроизведения | Не поддерживается |
| Сериализация отдельных объектов с JsonUtility | Поддержка чтения/записи с JsonUtility. Поддержка дополнительных типов объектов с EditorJsonUtility |
Поддержка чтения/записи с JsonUtility |
| SerializeReference | Поддерживаемые | Поддерживаемые |
| ISerializationCallbackReceiver | Поддерживаемые | Поддерживаемые |
| FormerlySerializedAs | Поддерживаемые | Не поддерживается |
Объекты могут иметь дополнительные поля, которые сериализирует только Редактор, например, когда вы декларируете поля в UNITY_EDITOR символ сценария:
public class SerializeRules : MonoBehaviour
{
#if UNITY_EDITOR
public int m_intEditorOnly;
#endif
}
В предыдущем примере, m_intEditorOnly поле сериализируется только в редакторе и не включается в сборку. Это позволяет сэкономить память, пропуская данные, которые требуются только в редакторе из вашей сборки. Любой код, использующий это поле, также должен быть условно компилирован, например, в #if UNITY_EDITOR блоки, чтобы класс компилировался во время сборки.
Редактор не поддерживает объекты с полями, которые Unity сериализирует только во время выполнения (например, когда вы объявляете поля в директиве UNITY_STANDALONE).