SerializeField in Unity: Everything You Need to Know
Introduction
In this article, I will explain everything you need to know about the SerializeField attribute in Unity.
By the end of this article, you will know what the SerializeField attribute does.
You will understand what types of fields are serializable. You will feel comfortable deciding when and where to use it in your code.
You will also learn about [System.NonSerialized] and [field:SerializeField] attributes.
Key Takeaways for SerializeField
- Use private fields and variables in your classes.
- If you want Unity to show a field in the Inspector, use the SerializeField attribute,
[SerializeField]
. - You use the SerializeField attribute like this:
[SerializeField] private int MaximumHealth;
What does SerializeField do?
SerializeField forces Unity to serialize a field.
If you understand what Serialization means, understanding SerializeField is easy.
Do you want to see and edit private values but don’t want the values saved?
So when you edit it, the changed value vanishes into the ether?
Why is it essential that the values not be serialized to disk?
And if that is important, what is the point of editing them if they disappear?
- Unity wants to draw all the fields in the class in the Inspector.
- But, it can only draw fields that are serialized on the disk.
- When you serialize the field, Unity has a copy on the disk that it can use to draw the field in the Inspector.
- When you change the value in the Inspector, you are changing the serialized object.
- Therefore, you must use SerializeField to enable Unity to draw an editable field in the Inspector.
In the next section, I’ll explain what Serialization means in Unity, offer an analogy, and a couple of examples.
What does Serialization mean in Unity?
In this section, I’ll explain what serializing a field in Unity means. I will explain how Serialization impacts your project.
Then, I will give an example of a serialized field, an implicitly serialized field, and a non-serialized field to illustrate how they work differently…
What is Serialization in Unity?
Other tutorials skip this topic. This tutorial will cover it. You must understand what Serialization is and how it applies to your project.
Serialization refers to a process wherein Unity extracts variable data from your class. Unity wants to extract this variable data so that when Unity reloads that class, it can put the variable data back where it was.
Time for an analogy. Imagine you are a sneaky little thief. Assume you have broken into someone’s house to find an important document. You need to find out where the document is, so you must dig around. You don’t want this person to know that you broke in, so you need to put everything back where you found it before you leave. As a reasonable person, you might take a few minutes to record (a.k.a Serialize) the state of the home so that you can make sure you put it back where it was when you entered.
When you reload your domain in Unity, Unity records (serializes) the state of your house (your scripts), bulldozes the entire house (your scripts), and then recreates the house (your scripts) based on the record (serialized version).
One scenario where a script reload happens is when you edit a script, save the script, then return to the Unity Editor. Boom: Hot Reload.
Listen up, this is important:
During Hot Reload, Unity will always serialize fields that can be serialized. This fact remains true even if it is a private field not marked with [SerializeField]
. Unity will Implicitly Serialize these fields.
You can specifically override this behavior by marking the field as [System.NonSerialized]
.
I made a small example that you can import to your project. Follow along for fun.
using System.Collections;
using UnityEngine;
[ExecuteAlways]
public class SerializeFieldExample : MonoBehaviour
{
[SerializeField]
private string mySerializedField = "My Serialized Field";
private string myImplicitSerializedField = "My Implicit Serialized Field";
[System.NonSerialized]
private string myNonSerializedField = "My Non-Serialized Field";
[SerializeField]
private bool reset = false;
private void OnValidate()
{
if (reset)
{
reset = false;
mySerializedField = "My Serialized Field";
myImplicitSerializedField = "My Implicit Serialized Field";
myNonSerializedField = "My Non-Serialized Field";
OnEnable();
}
}
private void OnEnable()
{
StartCoroutine(ModifyFields());
Debug.Log("On Enable.");
}
private void Update()
{
Debug.Log(mySerializedField);
Debug.Log(myImplicitSerializedField);
Debug.Log(myNonSerializedField);
}
IEnumerator ModifyFields()
{
yield return new WaitForSeconds(5f);
mySerializedField = "My Updated Serialized Field";
myImplicitSerializedField = "My Updated Implicit Serialized Field";
myNonSerializedField = "My Updated Non-Serialized Field";
}
}
In this example, we have three fields.
[SerializeField] private string mySerializedField = "My Serialized Field";
private string myImplicitSerializedField = "My Implicit Serialized Field";
[System.NonSerialized] private string myNonSerializedField = "My Non-Serialized Field";
This script will run in the Editor.
The Console logs the value of the three fields:
- “My Serialized Field”
- “My Implicit Serialized Field”
- “My Non-Serialized Field”
We’re going to wait five seconds. Then we’re going to change the value of each of these three fields.
The console logs the three fields.
- “My Updated Serialized Field”
- “My Updated Implicit Serialized Field”
- “My Updated Non-Serialized Field”
Now we will force a hot reload: Open the script, change something small, save it, and go back to Unity.
The console logs the three fields.
- “My Updated Serialized Field”
- “My Updated Implicit Serialized Field”
- “My Non-Serialized Field”
Huh? What’s that?
Unity correctly recorded and restored our SerializedField and implicitly SerializedField.
But, Unity did not put back our NonSerialized Field.
Unity typically tries to record each serializable field in the class before the Hot Reload. However, we marked one field as NonSerialized. This attribute forced Unity to ignore the NonSerialized field when it recorded the class variables before the Hot Reload.
When Unity reloaded the script, the variable is reset to the value written in the declaration:
myNonSerializedField = "My Non-Serialized Field".
Normally, it would restore the field to the serialized value. But in this case, the value is NonSerialized. Unity did not record a value before the Hot Reload. Therefore, it has nothing to restore to the value now that the Hot Reload is over.
Does Unity save Serialized Fields between Editor sessions?
Yes. If you modify a Serialized Field in the Inspector, Unity will save that value. If you close the Editor and re-open it, the Serialize Field will still have the value you set.
Does Unity save Serialized Fields between play sessions in the Editor?
No. If your game modifies a Serialized Field during gameplay while in Play mode in the Editor, Unity will reload the serialized value when you exit Play mode.
Does Unity save Serialized Fields between play sessions in a build?
In short, no. To save player data between sessions, you need to Serialize the data and save it on disk. To load that data later, you need to find the literal file to which you saved that data, deserialize it, and load it back to your game.
Unity never does this automatically for you, except in PlayerPrefs. In a separate tutorial, we will cover saving and loading in Unity and using PlayerPrefs.
What types of fields are Serializable?
In general, most types are serializable.
However, you will 100% run into a field that Unity cannot serialize on its own. So, this section will give you an idea of which fields are serializable so that you are less surprised when you get stuck later.
General Rules
In general, Unity is capable of serializing any instanced fields.
- Unity can serialize any field except static, const, or readonly fields.
- Public fields are serialized by default.
- Private fields are serialized if you use [SerializeField].
- Properties are methods that wrap fields, so they can’t be serialized. You can serialize the backing value, however. More on that later.
Serializable Field Types
Unity will serialize any primitive data type, any enum (which is a wrapper around the int type), any UnityEngine.Object, most Unity structs, any serializable class (e.g., any class that inherits from UnityEngine.Object), any serializable struct (e.g., many Unity structs), and any one-dimensional collection that is made up of a serializable type.
Unity will not serialize any multidimensional collections. Multidimensional collections include things like a c# dictionary or a multidimensional array.
Click here to check the Unity docs for more details.
Serialize the Backing Field of a Property
You can serialize the backing field for a property using an attribute, [field:SerializeField].
I will provide an example.
[field: SerializeField] public string MyProperty { get; private set }
Unity will expose the backing field in the Inspector. Any changes that you make are made directly to the backing field itself. You may have validation logic in the setter. Your change will not go through the setter, so it will not go through that verification logic. Unity modifies the backing field itself and completely ignores the property.
The NonSerialized attribute can also be applied to properties. You can force Unity to discard the value during a Hot Reload. To do this, use the NonSerialized attribute on the backing field. This is the same approach you would take for a normal field.
[field: System.NonSerialized] public string MyNonSerializedProperty { get; private set; }
When should I use SerializeField?
If you want Unity to show the Inspector field, use [SerializeField]. The field will be shown in the Inspector by marking the variable as serializable.
When should I use [System.NonSerialized]
If you want Unity to discard the field value and reset to the declaration value during a Hot Reload, use the [System.NonSerialized] attribute.
What is this [field: SerializeField] stuff about?
Suppose you want Unity to Serialize the backing field for a property. In that case, you can use the [field: SerializeField] attribute to set the attribute directly on the backing field. Ditto with [field: System.NonSerialized].
How do Static fields work?
Unity never restores static fields. Unity will always discard Static fields during the reload process. Never use static fields for states that you need to retain between reloads.
How do Constant fields work?
Constant fields never change from the declaration value. So the value for the constant field will always be the same before and after reloads.
You do not need to serialize a constant field because the field will never change. Fields declared readonly will also never change.
SerializeField vs. Public
Unity will also serialize a public field and expose it in the Inspector. So, why use SerializeField instead of public?
Well, these are two separate considerations.
[SerializeField] and [System.NonSerialized] are tools. These tools describe how Unity should treat the field for Serialization.
Public, private, and other access modifiers control how other classes can access fields.
If you make a field public, it is a billboard to other developers (including you in the future). The billboard says: “Please set my value from another class.”
Now, imagine that this field is your player’s health.
Do you want a billboard next to your player’s health that says, "Please change me"? Probably not.
Suppose that you use the [SerializeField] attribute with a private access modifier instead. Now you have taken down the billboard and replaced it with strong guardrails.
Other classes cannot access this field. These guardrails will help protect you from funky bugs.
Remember:
- You want to write code that is difficult to use incorrectly.
Should I use SerializeField or Public?
Decide the two questions of access and Serialization separately:
- Decide on the access modifier (public vs private) based on the access you want to provide to other classes.
- Decide on the Serialization attribute based on Serialization. Do you want the field to be serialized, implicitly serialized, or non-serialized.
Recommended Reading & Next Steps
https://docs.unity3d.com/ScriptReference/SerializeField.html
https://docs.unity3d.com/Manual/script-Serialization.html
https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html
Practice using [SerializeField], [System.NonSerialized]. Try to get comfortable using private as your default access modifier.
(P.S. private is the default access modifier in Unity).
Conclusion
Thanks for reading my tutorial on SerializeField in Unity! It took quite a while to research, write, and review.
At the beginning of this article, I made a few promises. I promised that you would know what [SerializeField] does. I promised you’d know which fields are serializable in Unity. I promised that you would feel comfortable using [SerializeField] in your projects. I also promised that you would learn about [System.NonSerialized] and [field:SerializeField].
If you have further questions, join the OccaSoftware Discord channel for game developers.