The wording definitely needs improvement.
I think this section applies to a different scenario than yours - it’s not about when the field type inside the class is polymorphic (which is a special case by itself and needs very careful handling anyway or even a redesign if possible), but when you don’t know to what class you need to deserialize.
Example scenario:
In an RPG you have your whole inventory serialized and saved somewhere.
All classes used in the Inventory derive from ItemBase. ItemBase has only 2 fields - UniqueID and ItemType (enum).
You deserialize each object as an ItemBase, parse Item.ItemType value into the enum and based on that parse the original JSON into the specialised class (Weapon, Armor, Potion etc.).
Example code (tested, works):
Long spoiler below.
Btw - this is how I would imagine a decent JsonUtility “real life” example would look like. Feel free to use in the Docs
Classes:
ItemBase
[Serializable]
public class ItemBase
{
public int UniqueID;
public ItemType ThisItemType;
private static int globalUniqueItemID = 0;
public ItemBase()
{
this.UniqueID = globalUniqueItemID;
globalUniqueItemID++;
}
public enum ItemType
{
Other,
Weapon,
Armor,
Potion
}
}
MyWeapon
[Serializable]
public class MyWeaponClass : ItemBase
{
public int MinDamage;
public int MaxDamage;
public MyWeaponClass() : base()
{
this.ThisItemType = ItemType.Weapon;
}
public MyWeaponClass(int minDmg, int maxDmg) : this()
{
this.MinDamage = minDmg;
this.MaxDamage = maxDmg;
}
public override string ToString()
{
return String.Format("UniqueID: {0}, ItemType: {1}, MinDamage: {2}, MaxDamage: {3}.", UniqueID, ThisItemType, MinDamage, MaxDamage);
}
}
MyArmor
[Serializable]
public class MyArmorClass : ItemBase
{
public float ArmorValue;
public string OriginalOwnerName;
public MyArmorClass() : base()
{
this.ThisItemType = ItemType.Armor;
}
public MyArmorClass(float armorValue, string firstOwner) : this()
{
this.ArmorValue = armorValue;
this.OriginalOwnerName = firstOwner;
}
public override string ToString()
{
return String.Format("UniqueID: {0}, ItemType: {1}, ArmorValue: {2}, FirstOwner: {3}.", UniqueID, ThisItemType, ArmorValue, OriginalOwnerName);
}
}
Sample “application”
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class JsonExample : MonoBehaviour
{
void Start()
{
// create 2 dummy items
MyArmorClass sampleArmor = new MyArmorClass(25.7f, "Awesome Joe");
MyWeaponClass sampleWeapon = new MyWeaponClass(10, 18);
// make a dummy inventory
List<ItemBase> myInventory = new List<ItemBase>();
myInventory.Add(sampleArmor);
myInventory.Add(sampleWeapon);
// print out the inventory
Debug.Log("==== printing original inventory ====");
foreach (var item in myInventory)
{
Debug.Log(item);
}
// serialize the whole inventory
List<string> myJsons = new List<string>();
foreach (var item in myInventory)
{
myJsons.Add(JsonUtility.ToJson(item));
}
// print out how the items look as json
Debug.Log("==== printing json serialized inventory ====");
foreach (string jsonString in myJsons)
{
Debug.Log(jsonString);
}
// pretend that the jsons are stored somewhere
// for example in a file or server
// and later retrieved as a list of strings
// deserialize back
List<ItemBase> myDeserializedInventory = new List<ItemBase>();
foreach (string jsonString in myJsons)
{
ItemBase unknownItem = JsonUtility.FromJson<ItemBase>(jsonString);
switch (unknownItem.ThisItemType)
{
case ItemBase.ItemType.Weapon:
MyWeaponClass tmpWeapon = JsonUtility.FromJson<MyWeaponClass>(jsonString);
myDeserializedInventory.Add(tmpWeapon);
break;
case ItemBase.ItemType.Armor:
MyArmorClass tmpArmor = JsonUtility.FromJson<MyArmorClass>(jsonString);
myDeserializedInventory.Add(tmpArmor);
break;
default:
Debug.LogError("Not implemented item type!");
break;
}
}
// print out the whole deserialized inventory
Debug.Log("==== printing deserialized inventory ====");
foreach (var item in myDeserializedInventory)
{
Debug.Log(item);
}
// count weapons
Debug.Log("Weapons: " + myDeserializedInventory.Where(x => x.ThisItemType == ItemBase.ItemType.Weapon).Count());
// count armor
Debug.Log("Armors: " + myDeserializedInventory.Where(x => x.ThisItemType == ItemBase.ItemType.Armor).Count());
// count total
Debug.Log("All items: " + myDeserializedInventory.Count());
}
}
Console output:
Also it would be nice if there would be some explanation of this part “The object you pass in is fed to the standard Unity serializer for processing, so the same rules and limitations apply as they do in the Inspector; only fields are serialized, and types like Dictionary<>are not supported.” so that it’s obviously clear what is and what isn’t serialized by it (it’s probably somewhere in the docs about inspector, so a link maybe?).