- Home /
Does Unity Serialization Support Inheritence?
I am having trouble saving custom child classes in my editor script. Data from the child classes is being lost. The question is, does Unity serialization support inheritance? Here is an example of the problem:
// Serialize
[System.Serializable]
public ParentClass()
{
public string someString = "a string";
}
[System.Serializable]
public ChildClass() : ParentClass
{
public int someInt;
public ChildClass(int _someInt)
{
someInt = _someInt;
}
}
List<ParentClass> list = new List<ParentClass>();
list.Add(new ChildClass(5));
// Data is saved
// Exit Unity
// Data is loaded
Debug.Log(list[0].someString);
// Output: a string; Works as intended
Debug.Log((list[0] as ChildClass).someInt));
// Null Reference Exception
Answer by Bunny83 · Apr 28, 2012 at 08:24 PM
Unity determine the instance type via the variable type. If you store a subclass in a base class variable it gets serialized as base class.
However there is a way to use inheritance with serialization: ScriptableObject.
Your base class has to be derived from ScriptableObject. In this case Unity will remember the true type when you store a sub / child class in a base-class variable.
ScriptableObjects have to be created with ScriptableObject.CreateInstance and destroyed with Destroy.
Unity fully supports only types derived from UnityEngine.Object. A "normal" class (derived from System.Object) is not really serialized. Unity just stores the serializeable fields it can find within the class that is actually serialized (for example a MonoBehaviour that holds the reference to an instance).
@Bunny83 ScriptableObject are not meant for inheritance but rather to save (dump) a class serialization into a file (asset), as can be read in the Scripting Reference.
@$$anonymous$$ryptos: Yes and no ;) A ScriptableObject is a fully supported type in Unity which get serialized as whole object, like $$anonymous$$onoBehaviour derived classes. You don't have to store a ScriptableObject in a seperate asset file. If you create an instance (for example via a custom editor) and reference this instance from a $$anonymous$$onoBehaviour in the scene, the ScriptableObject will get saved (serialized) along with the scene itself exactly like the $$anonymous$$onoBehaviour instances.
The difference between a ScriptableObject and a $$anonymous$$onoBehaviour is that a ScriptableObject doesn't need to be attached to a GameObject and it doesn't have Update / Start / ... callbacks.
The only alternative is to use $$anonymous$$onoBehaviour derived objects and attach them to a GameObject since they also support inheritance.
I've done this in my nodebased editor. I create an empty sub gameobject which works as container for my class instances. Those instances can be referenced in an array / List of the base type and will remember the actual reference.
Answer by vexe · Jan 04, 2015 at 11:15 AM
I know this might be old thread, but I'd like to share my solution in case someone in the future came across this question.
In order to overcome the limitations of Unity's serialization system you need to write your own custom system. With the help of ISerializationCallbackReceiver and a custom serializer, I was able to do just that in VFW. There's support for polymorphic types (interfaces and abstract system objects), generics, auto-properties, delegates, readonly fields, static fields/auto-props and much more.
Answer by kornel-l-varga · Apr 22, 2021 at 11:24 AM
I have found a great answer (not the accepted one) here by @Ruzihm : https://answers.unity.com/questions/1247233/derived-class-serialization.html
Use the [SerializeReference] decorator on the fields you want to keep their derivate values and type.
Answer by Tseng · Apr 28, 2012 at 04:13 PM
ParentClass do not expose someInt
variable, that's the reason why you can't access it. Unity (or Mono) is doing something strange there. If you want someInt
to be serialized and displayed in the inspector, you have to replace List<ParentClass> list
with List<ChildClass> list
.
Though this won't allow you to add ParentClass objects to the list, because they do not have someInt
. That's how inheritance works. With the "Parent class" as you call it, you can only access the most common denominator of all classes that are based on it.
To access the added members, you have to upcast it again
ParentClass parent = new ChildClass();
Debug.Log(parent.astring);
ChildClass child = (ChildClass)parent;
Debug.Log(child.someInt);
// or
Debug.Log( ((ChildClass)parent).someInt) );
If you could only reference an instance with its specific type that would make inheritance quite useless ;)
Answer by bompi88 · Apr 28, 2012 at 02:58 PM
Have you tried to keep each class in its own file? Like this:
ParentClass.cs :
using UnityEngine;
using System.Collections;
[System.Serializable]
public class ParentClass
{
public string someString = "a string";
}
ChildClass.cs :
using UnityEngine;
using System.Collections;
[System.Serializable]
public class ChildClass : ParentClass
{
public int someInt;
public ChildClass(int _someInt)
{
someInt = _someInt;
}
}
LoadAndWrite.cs :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LoadAndWrite : MonoBehaviour
{
void Start() {
List<ParentClass> list = new List<ParentClass>();
list.Add(new ChildClass(5));
// Data is saved
// Exit Unity
// Data is loaded
Debug.Log(list[0].someString);
Debug.Log((list[0] as ChildClass).someInt);
}
}
That's wrong. A public class is not automatically serialized. A public class won't even show in the inspector unless it's derived from UnityeEngine.Object
(which almost all of Unity base classes are).
If it's derived from UnityeEngine.Object
, then it will be serialized but as "object" selector (i.e. where you can drag objects containing SomeClassName (Prefabs, GameObjects from scene)). Only if your add the serialize attribute the members of the object will be exposed and serialized in the Inspector
Your answer
Follow this Question
Related Questions
prevent field json serialization in 5.3 0 Answers
JsonUtility not found / working 0 Answers
How to store references between scriptableobject assets 3 Answers
Trying to Use DataContractSerializer with 0 Answers
Unserialized private variable values from static instance persist when exiting play mode 1 Answer