OnBeforeSerialize is getting called rapidly?

Not sure if this is normal, but I noticed that OnBeforeSerialize is getting called very rapidly in-editor and at runtime - almost every frame.

using UnityEngine;   

public class Test : MonoBehaviour, ISerializationCallbackReceiver
{
    public void OnBeforeSerialize()
    {
        Debug.Log("before");
    }

    public void OnAfterDeserialize()
    {
        Debug.Log("after");
    }
}

I read in the docs that it’s called before Unity ‘reads’ my objects’ values - I don’t think ‘read’ is quite a synonym to ‘serialize’ - they’re using ‘read’/‘write’ to ‘serialization’/‘deserialization’ - not sure about that.

Is this how it’s supposed to work? (called very rapidly) - if so, I think they should have named it something else cause ‘OnBeforeSerialize’ is miss-leading, unless I’m miss-understanding something here.

Cheers!


EDIT:

So I thought maybe cause I’m using some Unity API (Debug.Log) which the doc states that it wouldn’t be preferred - but not the case, tried this:

public int counter;

public void OnBeforeSerialize()
{
	counter++;
}

And the value still changes very rapidly!

I would agree that “happens more often than you might think” doesn’t really equate to “every frame”.

Here’s what I found for OnBeforeSerialize:

  1. Called once before a recompile is handled by the Unity Editor
  2. Called multiple times when the scene is saved (ie two or three times)
  3. Called every frame if the inspector for the object is open in the editor
  4. Not called in an actual build (in my simple test)

Here’s what I found for OnAfterDeserialize:

  1. Called once after a recompile
  2. Called once after the scene is loaded
  3. Called once in an actual build (in my simple test)

So, if you have the editor open and an inspector open. OnBeforeSerialize is called every frame by the OnInspectorUpdate function. So far, there doesn’t seem to be a way for me to stop or interrupt this.

The documentation warns you that using this interface and the rapid calls right here:

Another caveat is that serialization happens more often than you might think. When a MonoBehaviour gets cloned through Instantiate() at runtime, it gets deserialized and serialized. If the object had a field that pointed to its own gameObject, when that gameObject gets cloned, you’d want the field to point to the new gameObject, not the old one. In order to update these “internal references”, Unity uses the serialization system. Unity reads all your fields, finds references to “things that were cloned”, and then writes the new values in your fields. The callbacks will also be invoked for this updating phase, allowing you to make the updating of internal references to also work in your custom classes that Unity cannot serialize.

This is an old thread, but here’s a workaround.

I have a ScriptableObject that have some properties exposed in the inspector, but I use the serialization callbacks to serialize a non-serializable data (as an example, I’m serializing a dictionary).

In order to avoid serialization if it’s not needed, I use the Unity’s dirty flag. This flag is enabled when an exposed property is changed in the inspector. So if this flag is set to true (and so a property has been modified), I let the serialization happen, then I remove the dirty flag.

public void OnBeforeSerialize()
{
    #if UNITY_EDITOR
    if(UnityEditor.EditorUtility.IsDirty(this);
    {
        SerializeDictionary();
        UnityEditor.EditorUtility.ClearDirty(this);
    }
    #else
    SerializeDictionary();
}

private void SerializeDictionary() { /* ... */ }