1

I have an some XML that I wish to serialize and deserialize using the XmlSerializer. I wish to be able to possibly use other serial formats in the future, such as JSON, YAML, etc, so my resulting classes from deserialization should share the same interface.

However, my interface contains an array of objects that also use an interface:

public interface IConfiguration
{
    ICommand[] Commands { get; set; }
}

public Interface ICommand
{
    // Command properties
}

[System.SerializableAttribute()]
public XmlConfiguration : IConfiguration
{
    ICommand[] Commands { get; set; }
}

[System.SerializableAttribute()]
public XmlCommand : ICommand
{
    // Command properties
}

How will the XML deserialize operation know to use the XmlCommand concrete type when creating the XmlConfiguration object?

Thinking as I type...

I guess I could add a constructor to the XmlConfiguration class to assign an empty array of the concrete type, but I am not sure if this would work as intended?

[System.SerializableAttribute()]
class XmlConfiguration : IConfiguration
{
    public XmlConfiguration()
    {
        Commands = new XmlCommand[] { };
    }
}

Update: I realize there is the XmlArrayItemAttribute attribute available, unsure if it will work for interfaces though:

class XmlConfiguration : IConfiguration
{
    [System.Xml.Serialization.XmlArrayItemAttribute(typeof(XmlCommand))]
    public ICommand[] Commands { get; set; }
}

Update: I can probably also do:

class XmlConfiguration : IConfiguration
{
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public ICommand[] Command
    {
        get => CommandsConcrete;
        set => CommandsConcrete = (XmlCommand[])value;
    }

    [System.Xml.Serialization.XmlElementAttribute(ElementName = "Commands")]
    public XmlCommand[] CommandsConcrete { get; set; }
}
2
  • You will need to include type info into xml somehow, not sure how is it done with interfaces, but with base class it's [XmlInclude] to list all inherited types. Can you switch to base class or use another serializer? I am quite sure json.net will manage it with TypeNameHandling.Auto. Commented Aug 24, 2017 at 12:44
  • @Sinatr I came across XmlIncludeAttribute but the example code on the MSDN page is blank... so I had little to go on how to properly apply it :( Commented Aug 24, 2017 at 12:46

1 Answer 1

2

To serialize interface property one easy possibility is to use another property. You still need to use [XmlInclude] for serializer to know all types what may occurs:

public interface ICommand
{
    string Text { get; set; }
}

public class CommandA : ICommand
{
    public string Text { get; set; }
}

public class CommandB : ICommand
{
    public string Text { get; set; }
}

[XmlInclude(typeof(CommandA))]
[XmlInclude(typeof(CommandB))]
public class Settings
{
    [XmlIgnore]
    public ICommand[] Commands { get; set; }

    [XmlArray(nameof(Commands))]
    public object[] CommandsSerialize
    {
        get { return Commands; }
        set { Commands = value.Cast<ICommand>().ToArray(); }
    }
}

Upon serialization this will produce

xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Commands>
    <anyType xsi:type="CommandA">
      <Text>a</Text>
    </anyType>
    <anyType xsi:type="CommandB">
      <Text>b</Text>
    </anyType>
  </Commands>
</Settings>
Sign up to request clarification or add additional context in comments.

2 Comments

Adding the attribute [XmlArrayItem("Command", typeof(Command))] to the CommandsSerialize property, allowed for nicer XML output for the <Command> element in the case where specific type information does not need to be retained
Also to note that as an alternative to adding the XmlInclude atributes, one could pass the additional types to the XmlSerializer constructor. However there are some issues with this, the largest being that the constructed serializer should be cached to protect against a big memory leak

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.