Store (serialze?) List with mixed types

I have a created a List for mixed Types for Xml serialization

using System.Collections.Generic;
using System;
using System.Xml.Serialization;

public class ConfigurationLayout
    {
        [XmlArray("ConfigurationItems")]
        [XmlArrayItem(Type = typeof(XmlVector3), ElementName = "Vector3")]
        [XmlArrayItem(Type = typeof(XmlQuaternion), ElementName = "Quaternion")]
        [XmlArrayItem(Type = typeof(XmlTransform), ElementName = "Transform")]
        [XmlArrayItem(Type = typeof(XmlInt), ElementName = "Int")]
        [XmlArrayItem(Type = typeof(XmlBool), ElementName = "Bool")]
        [XmlArrayItem(Type = typeof(XmlFloat), ElementName = "Float")]
        [XmlArrayItem(Type = typeof(XmlString), ElementName = "String")]
        [XmlArrayItem(Type = typeof(XmlList), ElementName = "List")]
        [XmlArrayItem(Type = typeof(ConfigurationItem))]
        public List<ConfigurationItem> ConfigurationItems = new List<ConfigurationItem>();
    }

Where all those types starting with Xml... are derived from ConfigurationItem.

 [Serializable]
 public class ConfigurationItem
 {
     [XmlAttribute]
     public ConfigurationItemType Type;

     [XmlAttribute]
     public string Name;

     public ConfigurationItem(){ }

     public ConfigurationItem(string name, ConfigurationItemType type)
     {
         Name = name;
         Type = type;
     }
 }

[Serializable]
public class XmlInt : ConfigurationItem
{
    [XmlAttribute]
    public int Value;

    public XmlInt() : base(null, ConfigurationItemType.Int) { }

    public XmlInt(string name) : base(name, ConfigurationItemType.Int) { }

    public XmlInt(string name, int value) : base(name, ConfigurationItemType.Int)
    {
        Value = value;
    }
}

Later I can add specific items e.g. using

 [...].ConfigurtationItems.Add(new XmlInt(<string : Name>,<Int : Value>));

If I now write the Xml file using

using (FileStream file = File.Create(CompleteFilePath))
{
    using (var writer = new StreamWriter(file, Encoding.UTF8))
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationLayout));
        serializer.Serialize(writer, ConfigFile);
     }
}

I get as expected in the Xml File somthing like

<?xml version="1.0" encoding="utf-8"?>
<ConfigFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ConfigurationItems>
    <Int Type="Int" Name="asd" Value="0" />
  </ConfigurationItems>
</ConfigFile>

BUT

Anyway in the ScriptableObject there is only the Data stored for ConfigurationItem not for e.g. XmlInt.

...
  ConfigFile:
    ConfigurationItems:
    - Type: 0
      Name: asd

But the value is not stored so when I try to acces it

var bla = ((XMLInt) ConfigFile.ConfigurationItems[0]).Value;

it claims (justifiably)

NullReferenceException: Object reference not set to an instance of an object


The interesting thing for me is that it actually works as soon as I don’t reload or rebuild the Scene.
So for a certein time the List is actually stored with the correct types within Unity but the problem is only when saving the asset/scene and serialization starts.

Is there a way to make such a mixed type List stored correctly (and how)?


###EDIT

I forgot to mention that it works totall fine, if I reload the before saved XML File (since than I just add the items again with their according type) so the XML serialization is not the problem but Unities.

No you can’t make it work somehow since Unity’s serialization system does not support polymorphism for custom serializable classes, only for types derived from ScriptableObject or MonoBehaviour. See the Script Serialization manual page. Custom serializanle classes are basically treated like structs. They are always serialized based on the field type, not the actual type. Those classes aren’t even serialized as objects but their data is simply serialized “inline” in the outer ScriptableObject / MonoBehaviour. So no type information is serialized, only data. See the example YAML scene file. To better understand your specific problem you may want to set your asset serialization mode to “force text” and view the serialized data (scene file, prefab, asset) in a normal text editor.

Only references to classes derived from UnityEngine.Object can be serialized as all objects derived from UnityEngine.Object are “standalone” assets. They are serialized as seperate objects unlike custom serializable classes. The only base classes you can derive your own type from are ScriptableObject and MonoBehaviour (for the runtime) and some more ScriptableObject based classes for the editor (Editor, EditorWindow, ScriptableWizard, …)

These situations are usually solved by polymorphism, either with interfaces or abstract base classes. In the worst case you can have a type enum or int variable and switch the type based on the type variable’s value (but I really recommend polymorphism instead, if possible).

So I don’t know if this would work (I don’t know if XmlSerializer has some special requirements), but I would make ConfigurationItem an abstract base class and create a public abstract XmlSerializer GetSerializer (); function, and override it in each specific type. Maybe it would be enough for the override to just return new XmlSerializer(typeof(<the class you are in>);.