views:

454

answers:

1

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.

+2  A: 

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.

arbiter
But what about the underlying Dictionary? If I do what you suggested, will it know when it goes to an entry of the subSettings field, statically typed as a SubSettings, that it should be serialized as a CoolSubSettings?
Dov
Underlying logic is up to you. As long as you provide correct (and recognized by serializer) types, everything must work fine. For example in get property you must fill result array with correct DictEntry<T> types based on your dictionary value types.
arbiter
I think I understand what you're saying, and I'm going to try it out. In terms of inheritance, CoolSubSettings inherits from SubSettings, so that won't be an issue.
Dov
That did it, thanks a lot. I was able to work out the rest based on your advice.
Dov