C# – How to serialize/deserialize a list of objects with a common root class

cinheritancexmlxml-serialization

Related: How can I use polymorphism in XML Serialization?

I have a class I wrote for serializing the user's preferences to disk between application sessions. To read/write I'm using XmlSerializer.Deserialize() and XmlSerializer.Serialize(). One property that gets serialized is a list of sub-settings for different application components. To accomplish this, I have something like the following (the property is only used during serialization):

private readonly Dictionary<SettingType, SubSettings> subSettings;    

[XmlArray("SubSettings")]
[XmlArrayItem("SubSetting", Type=typeof(DictionaryEntry))]
public DictionaryEntry[] _SubSettings
{
    get
    {
        int i = 0;

        //Make an array of DictionaryEntries to return 
        DictionaryEntry[] result = new DictionaryEntry[subSettings.Count];

        foreach( KeyValuePair<SettingType, SubSettings> setting in subSettings ) {
            DictionaryEntry entry = new DictionaryEntry( setting.Key, setting.Value );
            result[i] = entry;
            i++;
        }

        return result;
    }
    set
    {
        subSettings.Clear();
        for( int i = 0; i < value.Length; i++ )
            subSettings.Add( (SettingType)value[i].Key, (SubSettings)value[i].Value );
    }
}

That's been serving me perfectly well, with all the dictionary's values being SubSettings dynamically. The problem is that now I'd like to have some of the SubSettings objects be a different dynamic type (CoolSubSettings : SubSettings). The obvious problem is that if I do this, I won't be able to communicate as the XML is read what dynamic type each SubSettings node is supposed to be, and its additional properties will not be read or written.

Best Answer

This is because serializer does not know all the types, you must tell him which types it must use. For example, you cant try the following approach:

struct DictEntry<T>
{
   public SettingType Key;
   public T Value;
}

// ...

[XmlArray("SubSettings")]
[XmlArrayItem("SubSetting", Type=typeof(DictEntry<SubSettings>))]
[XmlArrayItem("CoolSubSetting", Type=typeof(DictEntry<CoolSubSettings>))]
public object[] _SubSettings
{
    // ...

Update: Yet another solution for your problem:

struct DictEntry
{
    public SettingType Key;        
    [XmlElement("SubSettingValue", Type=typeof(SubSettings))]        
    [XmlElement("CoolSubSettingValue", Type=typeof(CoolSubSettings))]
    public object Value;
}

[XmlArray("SubSettings")]
public DictEntry[] _SubSettings
{
    // ...

I think you understand main implementation idea? BTW, I am not sure about inheritance in this case, and I cannot test it right now. But in case of troubles you can create basic ancestor for both SubSettings and CoolSubSettings.