Unity 6.3
0 онлайн 62 гостей 3 в системе
Вход

SerializeReference

класс в UnityEngine

Выполнено в:UnityEngine.CoreModule

Описание

Помечает поле, которое должно быть серийизовано как ссылка, а не как значение.

См. страницу manual serialization page для информации о сериализации и полных правилах сериализации.

Без использования атрибута [SerializeReference], Unity сериализирует каждое из полей объекта по значению или по ссылке, в зависимости от типа поля, и согласно следующим правилам сериализации:

  • UnityEngine.Object поля, по ссылке:
    Если тип поля выведен из UnityEngine.Object, Unity сериализирует его как ссылку на этот объект. Например, MonoBehaviour, который определяет поле Transform. Поля, которые ссылаются на UnityEngine.Object таким образом, не требуют атрибута SerializeReference, потому что сериализация для поля всегда записывает ссылку на независимо-сериализированный объект.

  • Другие типы полей, по значению:
    Если тип поля является таким, что Unity может автоматически сериализировать по значению (простые типы полей, такие как int, string, Vector3, и т. д.) либо если это пользовательский сериализуемый класс или структура, помеченные [Serializable] атрибут, он сериализируется как значение.

В случае пользовательского сериализуемого класса это означает, что сериализуется только данные, относящиеся к объекту поле, а не ссылка на сам объект. Для того, чтобы Unity для серийного кодирования этих типов полей в качестве справки, используйте [SerializeReference] атрибут.

Сериализация как ссылка, а не как значение может потребоваться в следующих случаях:

  • Вам нужны несколько ссылок на один и тот же экземпляр пользовательского сериализуемого класса.
    Например, серийизация ссылок необходима для топологий, основанных на ссылках, которые основаны на пользовательских классах, поддающихся серийизации (таких как связанные списки, деревья или циклические графы). Это происходит потому, что серийизация по умолчанию, основанная на значениях, хранит каждую ссылку как отдельную копию объекта, в то время как поля первоначально имели общую ссылку на один и тот же объект. В частности, если вы серийизируете структуру данных циклического графа, вы должны использовать SerializeReference для надлежащего сохранения графа и избежания потенциальных заморочек или сбоев, которые могут возникнуть из-за подхода серийизации по умолчанию.

  • Вам нужен полиморфизм для полей, тип которых — пользовательский сериализуемый класс.
    Если вы пытаетесь использовать полиморфизм на пользовательских сериализуемых классах без [SerializeReference] атрибута, дополнительные поля ваших производных классов не будут сохранены, и ваш объект будет вместо этого сериализирован, как если бы это был объявленный тип поля. SerializeReferencePolymorphismExample class below.

  • Вы хотите сериализовать нулевые значения.
    Сериализация на основе значений не может представлять null. Без использования SerializeReference нулевые значения заменяются встроенным объектом, который имеет неназначенные поля в сериализированных данных. Использование SerializeReference позволяет хранить нулевые ссылки.

Оптимизация

Сериализация по значениям более эффективна, чем использование SerializeReference с точки зрения хранения, памяти и времени загрузки и сохранения, поэтому SerializeReference следует использовать только в ситуациях, когда это необходимо.

Узел и управляемые ссылки

В контексте SerializeReference, ваш объект, который специализируется MonoBehaviour, ScriptableObject, ScriptedImporter или другой класс UnityEngine называется хост-объект. Вы можете использовать SerializeReference непосредственно на полях объекта хоста, или косвенно на полях пользовательских структур или классов, которые серийизованы внутри объекта хоста.

Объекты, назначенные полям с [SerializeReference] атрибут в объекте хоста управляемые ссылки. Каждая управляемая ссылка имеет уникальный ID, который MonoBehaviour, ScriptableObject или другой хост-объект, содержащий [SerializeReference] По умолчанию Unity генерирует этот ID автоматически; чтобы указать ID, используйте ManagedReferenceUtility.SetManagedReferenceIdForObject.

При использовании SerializeReference объекты управляемых ссылок доступны как общие ссылки только внутри того объекта-владельца, в котором они объявлены. При сериализации объекта-владельца все объекты управляемых ссылок сериализуются в раздел «references» — список, идущий после сериализации обычных полей. У каждого такого объекта есть запись в списке с его идентификатором, полным именем класса и значениями полей.

Вы можете увидеть эти данные, если вы используете по умолчанию "принудительный текст" режим сериализации ассетов. Чтобы сделать это, назначьте один из примерных скриптов ниже GameObject, сохраните сцену, затем откройте .unity файл сцены в текстовом редакторе. Данные каждой управляемой ссылки хранятся в файле .unity файл, в разделе "references:" сериализированных данных MonoBehaviour.

Управляемые ссылки не разделяются между разными экземплярами UnityEngine.Object. Если присвоить один и тот же объект пользовательского сериализуемого класса полям двух разных объектов-владельцев, сериализованные ссылки станут отдельными экземплярами. Кроме того, при клонировании объекта-владельца с управляемыми ссылками создаются отдельные копии всех объектов, на которые они ссылаются.

Чтобы совместно использовать ссылки на значения между несколькими объектами хоста, используйте ScriptableObject вместо SerializeReference. ScriptableObject позволяет группировать связанный набор данных вместе в качестве ассета. Поскольку ScriptableObject происходит от UnityEngine.Object, вы можете совместно использовать ссылки на них вне индивидуального объекта хоста. Правила сериализации по-прежнему применяются к полям на ScriptableObject, однако, вам может потребоваться использовать [SerializeReference] атрибут для полей внутри вашего класса, производного от ScriptableObject.

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

  • Обычный класс
  • Абстрактный класс
  • Интерфейс
  • System.Object

Значение, назначенное поле с атрибутом SerializeReference, должно, если оно не является нулевым, соответствовать следующим правилам:

  • Должен быть экземпляром пользовательского класса с атрибутом [Serializable].
  • Должен быть экземпляром типа поля или типа, который производится от этого типа.
  • Не должно происходить от UnityEngine.Object. Например, оно не может быть GameObject, MonoBehaviour, ScriptableObject или Transform.
  • Не должно быть C# Тип значения. Поэтому простые типы, такие как целые числа, а также структуры не поддерживаются, и должны быть сериализованы без атрибута [SerializeReference].
  • Не должен быть C# Словарем или другим типом, который не поддерживается Unity сериализацией

Примечания по использованию SerializeReference с массивами и списками:

  • Unity поддерживает серийизацию массивов и списков объектов по ссылкам.
  • Для массивов и полей List<T> атрибут SerializeReference применяется к элементам массива или списка, а не к самому массиву или объекту списка.
  • Вы не можете назначить массив или список полю типа System.Object. Вместо этого тип поля должен быть явно объявлен как массив или список.
    Это показано в следующем примере:

    [SerializeReference] public System.Object a = new List<MyCustomClass>(); // UNSUPPORTED
    [SerializeReference] public List<MyCustomClass> a = new List<MyCustomClass>(); // VALID

Другие примечания:

  • Animation не поддерживается на полях объектов ссылки, когда объект хоста происходит от ScriptableObject или ScriptedImporter.
  • Когда типы, на которые ссылается SerializeReference, больше не доступны при десериализации, Unity заменяет экземпляр на null, но сериялизованная информация сохраняется. Для дополнительной информации см. SerializationUtility.HasManagedReferencesWithMissingTypes

См. также: SerializedProperty.managedReferenceValue, MonoBehaviour, SerializationUtility, ManagedReferenceUtility.

using System;
using UnityEngine;

public class SerializeReferencePolymorphismExample : MonoBehaviour { [Serializable] public class Base { public int m_Data = 1; }

[Serializable] public class Apple : Base { public string m_Description = "Ripe"; }

[Serializable] public class Orange : Base { public bool m_IsRound = true; }

// Use SerializeReference if this field needs to hold both // Apples and Oranges. Otherwise only m_Data from Base object would be serialized [SerializeReference] public Base m_Item = new Apple();

[SerializeReference] public Base m_Item2 = new Orange();

// Use by-value instead of SerializeReference, because // no polymorphism and no other field needs to share this object public Apple m_MyApple = new Apple(); }
using System;
using System.Text;
using UnityEngine;

public class SerializeReferenceLinkedListExample : MonoBehaviour { // This example shows a linked list structure with a single int per Node. // This would be much more efficiently represented using a List<int>, without any SerializeReference needed. // But it demonstrates an approach that can be extended for trees and other more advanced graphs

[Serializable] public class Node { // This field must use serialize reference so that serialization can store // a reference to another Node object, or null. By-value // can never properly represent this sort of self-referencing structure. [SerializeReference] public Node m_Next = null;

public int m_Data = 1; }

[SerializeReference] public Node m_Front = null;

// Points to the last node in the list. This is an // example of a having more than one field pointing to a single Node // object, which cannot be done with "by-value" serialization [SerializeReference] public Node m_End = null;

SerializeReferenceLinkedListExample() { AddEntry(1); AddEntry(3); AddEntry(9); AddEntry(81); PrintList(); }

private void AddEntry(int data) { if (m_Front == null) { m_Front = new Node() {m_Data = data}; m_End = m_Front; } else { m_End.m_Next = new Node() {m_Data = data}; m_End = m_End.m_Next; } }

private void PrintList() { var sb = new StringBuilder(); sb.Append("Link list contents: "); var position = m_Front; while (position != null) { sb.Append(" Node data " + position.m_Data).AppendLine(); position = position.m_Next; } Debug.Log(sb.ToString()); } }
using System;
using System.Collections.Generic;
using UnityEngine;

public interface IShape {}

[Serializable] public class Cube : IShape { public Vector3 size; }

[Serializable] public class Thing { public int weight; }

[ExecuteInEditMode] public class BuildingBlocks : MonoBehaviour { [SerializeReference] public List<IShape> inventory;

[SerializeReference] public System.Object bin;

[SerializeReference] public List<System.Object> bins;

void OnEnable() { if (inventory == null) { inventory = new List<IShape>() { new Cube() {size = new Vector3(1.0f, 1.0f, 1.0f)} }; Debug.Log("Created list"); } else Debug.Log("Read list");

if (bins == null) { // This is supported, the 'bins' serialized field is declared as a collection, with each entry as a reference. bins = new List<System.Object>() { new Cube(), new Thing() }; }

if (bin == null) { // !! DO NOT USE !! // Although this is syntactically correct, it is not supported as a valid serialization construct because the 'bin' serialized field is declared as holding a single reference type. bin = new List<System.Object>() { new Cube() }; } } }