It wouldn’t be strange to expect 1 allocation. That of the Test object. It also wouldn’t be strange to expect 2 allocations. One for the Test Object, one for a Trouble object. The correct answer is 729. The serializer does not support null. If it serializes an object, and a field is null, we just instantiate a new object of that type, and serialize that. Obviously this could lead to infinite cycles, so we have a relatively magical depth limit of 7 levels. At that point we just stop serializing fields that have types of custom classes/structs and lists and arrays.
Since so many of our subsystems build on top of the serialization system, this unexpectedly large serialization stream for the Test monobehaviour will cause all these subsystems to perform more slowly than necessary. When we investigate performance problems in customer projects, almost always do we find this problem. We added a warning for this situation in Unity 4.5.
No support for polymorphism
if you have a public Animal[] animals and you put in an instance of a dog, a cat and a giraffe, after serialization, you will have three instances of Animal.
One way to deal with this limitation is to realize that it only applies to “custom classes”, which get serialized inline. References to other UnityEngine.Objects get serialized as actual references, and for those polymorphism does actually work. You’d make a ScriptableObject derived class or another MonoBehaviour derived class, and reference that. The downside of that is that you need to store that monobehaviour or scriptable object somewhere, and cannot serialize it inline nicely.
The reason for these limitations is that one of the core foundations of the serialization system is that the layout of the datastream for an object is known ahead of time, and depends on the types of the fields of the class, instead of what happens to be stored inside the fields.
I want to serialize something that Unity’s serializer doesn’t support. What do I do?
In many cases the best approach is to use serialization callbacks. They allow you to be notified before the serializer reads data from your fields and after it is done writing to them. You can use this to have a different representation of your hard-to-serialize data at runtime than when you actually serialize. You’d use these to transform your data into something Unity understands right before unity wants to serialize it, and you use it to transform the serialized form back into the form you like to have your data in at runtime right after unity has written the data to your fields.
Let’s say you want to have a tree datastructure. If you let Unity directly serialize the data structure, the “no support for null” limitation would cause your datastream to become very big, leading to performance degratations in many systems: