Instructs Unity to serialize a field as a reference instead of as a value.
By default Unity serializes a field as a value, unless the field type is derived from UnityEngine.Object, which is not supported by the default serialization. However, value serialization has some specific limitations. Value serialization does not support polymorphic fields so reference-based topologies, such as graphs, cannot be expressed natively with this technique.
SerializeReference is the simplest method to serialize polymorphic fields natively. To use it, add the [SerializeReference]
attribute to a polymorphic object field. Unity then serializes that object by reference when you run your code.
Alternatively, you can derive the field type from a ScriptableObject instead of serializing your UnityEngine.Object field as a reference. Using ScriptableObjects usually results in better performance than SerializeReference when the field is serialized. Storing the data in a ScriptableObject is less resource intensive than serializing by reference because of the complexity involved in serializing polymorphic fields, so while it is possible to serialize individual fields by reference using this attribute, it is often better to group data that you want to serialize by reference together into a ScriptableObject and use that instead.
The objects serialized with the SerializeReference attribute are referred to as "Managed References". The MonoBehaviour, ScriptableObject or other "host" object
that contains the [SerializeReference]
fields associates a unique ID with each managed reference. This ID is typically automatically generated, but it can be specified
using SerializationUtility.SetManagedReferenceIdForObject.
Note: When using SerializeReference, the referenced values cannot be shared between UnityEngine.Object instances. As an example, two different MonoBehaviours cannot share data from a single object that is serialized by reference. You should use ScriptableObjects to share data in this way instead of SerializeReference.
You can serialize both abstract and interface field types with this attribute, but not types that specialize UnityEngine.Object. The field Unity serializes can be null, but can’t be a specific specialization of a generic type.
For generic lists and array fields, the attribute applies to the elements of the list or array and not to the array or list object itself. Additionally, when you use lists with this attribute, you need to explicitly declare the type as a list before instantiation. For example, in this line below, the List type is explicitly declared in the variable declaration, rather than using var
or specifying the type as System.Object
. This is because Unity needs to know that the object has an implicit size which it needs to serialize in its entirety.
[SerializeReference] public List<System.Object> a = new List<System.Object>() {};
Other notes:
The field value can be a class derived from the field type.
The field type can be an interface, or abstract.
The types 'System.Object', 'List<System.Object>' and 'System.Object[]' are supported for the field type.
Neither the field type, nor the assigned object, can be of a type that specializes UnityEngine.Object.
The field type cannot be a specific specialization of a generic type(inflated type).
Fields on referenced objects cannot be animated.
See Also: 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<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() }; } } }