C# serialization with polymorphism/inheritance.

Hello,

on the one hand, I read a couple of times that a class derived from ScriptableObject can not be serialized.
And indeed I experience the Exception myself which gets thrown when trying to serialize a SO.

SerializationException: Type ScriptableObject in assembly Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null is not marked as serializable.

On the other hand I always read that inheritance/polymorphism can only be handled correctly on serialization when deriving from SO. I’m confused.

I don’t get how you have to build the class structure in order to serialize objects which use inheritance.
Atm my structure is like this:

public class Model : ScriptableObject {
}

[Serializable]
public class CreatureModel : Model {
    // A couple of primitive types to serialize.
}

[Serializable]
public class CitizenModel : CreatureModel {
     // A couple of primitive types to serialize.
}

This of course throws an exception that Model isn’t marked as serializable. Marking it as serializable will throw the excpetion from above. There is something I don’t get about this, what is it? :slight_smile:

You have to distinguish two things:

  • C# / .NET serialization
  • Unity’s built-in asset serialization

The ScriptableObject class can only be used for asset serialization inside the Unity editor. “Normal” .NET serialization only works with classes which are marked as Serializable.

You can’t create an instance of ScriptableObject with “new”. It has similar limitations as the MonoBehaviour class. ScriptableObjects have to be created with “CreateInstance” while MonoBehaviours can only be created with AddComponent. Both can also be created by cloning an existing object with Instantiate. Asset serialization can only be done inside the Unity editor while “asset deserialization” is also done in the runtime. So you can’t use Unity’s serialization system to save something at runtime. You have to use other methods. Either build your own system or use .NET serialization.

With .NET serialization you can only serialize classes which can be serialized. A lot built-in types like MonoBehaviour, ScriptableObject, Mesh, … are not serializable as they have a native counterpart on the C++ side. But also some seemingly pure managed types as Vector3 aren’t marked as serializable. So you have to use wrappers for those.

The point of ScriptableObjects inside the Unity editor is to provide a way to serialize a custom class on it’s own (again, only inside the editor) as seperate asset. Unity’s serialization system doesn’t store type information in the serialized data except for built-in types. That’s why inheritance works for those. If you use a custom serializable class inside a MonoBehaviour, the fields of that custom class are serialized along with the MonoBehaviour. This serialization happens based on the field type inside the MonoBehaviour class. That’s why you get an instance of the baseclass even when you stored a derived class inside the field. This feature is ment to allow a MonoBehaviour / ScriptableObject to structure it’s data. References to built-in Unity types are actually serialized as asset-reference. You can only reference assets which are serialized as seperate asset. So a field that holds a ScriptableObject reference just contains an asset reference. That’s why the field can have a baseclass type and the actual asset (which is stored seperately) can have a derived type.

If you want to understand Unity’s system better, go to your editor project settings and switch the asset serialization to “force text”. That way you can look at scene files or prefab files with a texteditor. It helps to understand how the system works. Though since you mainly seem to be interested in runtime serialization you can juse ignore everything that is related to Untiy serialization as it doesn’t work at runtime. At least up until now. Maybe we get such a feature in the future.