Описание
Указывает Unity сериализовать поле как ссылку, а не как значение.
По умолчанию Unity сериализует поле как значение, если тип поля не является производным от UnityEngine.Object, который не поддерживается сериализацией по умолчанию. Однако сериализация значений имеет определенные ограничения. Сериализация значений не поддерживает полиморфные поля, поэтому топологии на основе ссылок, такие как графы, не могут быть выражены с помощью этого метода.
SerializeReference – это простейший метод сериализации полиморфных полей. Чтобы использовать его, добавьте атрибут [SerializeReference]
в поле полиморфного объекта. Затем Unity сериализует этот объект по ссылке при запуске кода.
Кроме того, вы можете получить тип поля из ScriptableObject вместо сериализации поля UnityEngine.Object в качестве ссылки. Использование ScriptableObjects обычно приводит к более высокой производительности, чем SerializeReference, когда поле сериализуется. Хранение данных в ScriptableObject менее ресурсоемко, чем сериализация по ссылке, из-за сложности, связанной с сериализацией полиморфных полей, поэтому, хотя можно сериализовать отдельные поля по ссылке с помощью этого атрибута, часто лучше сгруппировать данные, которые вы хотите сериализовать по ссылке вместе в ScriptableObject и использовать вместо этого.
Объекты, сериализованные с помощью атрибута SerializeReference, называются "управляемыми ссылками". MonoBehaviour, ScriptableObject или другой "основной" объект
который содержит поля [SerializeReference]
, связывает уникальный идентификатор с каждой управляемой ссылкой. Этот идентификатор обычно генерируется автоматически, но его можно указать
с помощью SerializationUtility.SetManagedReferenceIdForObject.
Примечание. При использовании SerializeReference ссылочные значения не могут использоваться совместно экземплярами UnityEngine.Object. Например, два разных MonoBehaviours не могут совместно использовать данные из одного объекта, сериализованного по ссылке. Для обмена данными таким образом следует использовать ScriptableObjects вместо SerializeReference.
С помощью этого атрибута можно сериализовать как абстрактные, так и интерфейсные типы полей, но не типы, которые специализируются на UnityEngine.Object. Поле, которое Unity сериализует, может быть нулевым, но не может быть конкретной специализацией универсального типа.
Для общих списков и полей массива атрибут применяется к элементам списка или массива, а не к самому массиву или объекту списка. Кроме того, при использовании списков с этим атрибутом необходимо явно объявить тип как список перед созданием экземпляра. Например, в этой строке ниже тип List явно объявлен в объявлении переменной, вместо использования var
или указания типа как System. Объект
. Это связано с тем, что Unity необходимо знать, что объект имеет неявный размер, который необходимо полностью сериализовать.
[SerializeReference] public List
Другие примечания:
- Значением поля может быть класс, производный от типа поля.
- Тип поля может быть интерфейсным или абстрактным.
- Типы «System.Object», «List
» и «System.Object[]» поддерживаются для типа поля. - Ни тип поля, ни назначенный объект не могут относиться к типу, специализирующемуся на UnityEngine.Object.
- Тип поля не может быть конкретной специализацией универсального типа (расширенного типа).
- Поля на объектах, на которые есть ссылки, нельзя анимировать.
Смотрите так же: SerializedProperty.managedReferenceValue, MonoBehaviour, SerializationUtility.
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, 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 inventory;
[SerializeReference]
public System.Object bin;
[SerializeReference]
public List bins;
void OnEnable()
{
if (inventory == null)
{
inventory = new List()
{
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() { 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() { new Cube() };
}
}
}