Course contentsShow
← Unity Game Development
Lesson 286 of 8284. Prefabs and Data ManagementFree lesson

Managing Non-Serializable Data with Serialization Callbacks

Learners will implement ISerializationCallbackReceiver to handle complex data types that require manual processing before and after the serialization process.

In this lesson, you will learn how to use ISerializationCallbackReceiver to manually process data that Unity’s default serialization system cannot handle on its own.

The Serialization Challenge

Unity automatically saves and loads data for your scripts based on specific rules: it handles public variables and those marked with [SerializeField]. However, some data types—like Dictionary<TKey, TValue> or complex class structures—are not natively serializable. If you try to save these in the Inspector or across a scene reload, the data simply vanishes.

Bridging the Gap

The ISerializationCallbackReceiver interface allows you to step into the "before" and "after" of the serialization process. It provides two methods:

  1. OnBeforeSerialize(): Triggered right before Unity saves your data. This is where you convert your complex, non-serializable data (like a Dictionary) into a format Unity can read, such as two separate List arrays (keys and values).
  2. OnAfterDeserialize(): Triggered right after Unity loads your data. This is where you take those simple lists and reconstruct your complex data structure back into a usable Dictionary.

Implementation Example

Here is how you would bridge a Dictionary so it survives a scene save:

using System.Collections.Generic;
using UnityEngine;

public class InventoryManager : MonoBehaviour, ISerializationCallbackReceiver
{
    public Dictionary<string, int> inventory = new Dictionary<string, int>();

    [SerializeField] private List<string> keys = new List<string>();
    [SerializeField] private List<int> values = new List<int>();

    public void OnBeforeSerialize()
    {
        keys.Clear();
        values.Clear();
        foreach (var kvp in inventory)
        {
            keys.Add(kvp.Key);
            values.Add(kvp.Value);
        }
    }

    public void OnAfterDeserialize()
    {
        inventory.Clear();
        for (int i = 0; i < keys.Count; i++)
            inventory[keys[i]] = values[i];
    }
}

By using these callbacks, you keep your code clean while ensuring that complex logic remains consistent across the Unity serialization lifecycle. You aren't forced to change your runtime data structures just to satisfy Unity’s storage constraints; instead, you provide a "translator" that runs automatically in the background.

Key Takeaway: Use ISerializationCallbackReceiver to bridge the gap between complex runtime data structures and Unity's rigid serialization rules by manually packing and unpacking data.