Reputation: 513
I've got an xml file with a collection that looks like this
<AbstractCollection>
<ConcreteA name="Bob" age="4"/>
<ConcreteB name="Tree" size="1" />
</AbstractCollection>
I know that if I use a concrete collection - i.e. the two elements were the same type - it would be easy to use the standard XML deserialisation in C#. The different types seem to make it more difficult.
Is there a way to use the simple xml deserialisation to get this out, or do I have to implement deserialisation myself?
[Added for clarity] I should add that the xml already exists and I can't change it. I'm receiving messages in xml that take a form like that above. A more concrete example would be:
<Actions>
<Walked name="Bob" distance="4"/>
<Cycled name="Jane" gear="3rd" />
</Actions>
What I want to end up with is a "Cycled" and a "Walked" object. Oh, and to make it extra fun, the order is important.
Also, I've tried using XmlInclude attributes in the code, but that works by changing the xml when you serialise it (unless I've been using it wrong of course).
Upvotes: 0
Views: 98
Reputation: 513
So I found the solution, thanks to this answer.
The key was to use XmlElementAttribute
to change the way that the different classes were serialized.
The only strange part was that I found I had to create a wrapper class for the list, or else the Cycled and Walked elements aren't wrapped in a root element.
I know that the namespace stuff is still there, but I can deal with that - the problem of getting the derived classes has been solved!
Thanks to everyone who chipped in.
[Serializable]
public class Actions
{
[XmlElementAttribute("Walked", typeof(WalkedAction))]
[XmlElementAttribute("Cycled", typeof(CycledAction))]
public List<Action> ActionList { get; set; }
}
[Serializable]
public abstract class Action
{
[XmlAttribute]
public string Name { get; set; }
}
[Serializable]
public class WalkedAction : Action
{
[XmlAttribute]
public int Distance { get; set; }
}
[Serializable]
public class CycledAction : Action
{
[XmlAttribute]
public string Gear { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var actionList = new Actions();
actionList.ActionList = new List<Action>();
actionList.ActionList.Add(new WalkedAction { Name = "Bob", Distance = 4 });
actionList.ActionList.Add(new CycledAction { Name = "Jane", Gear = "3rd" });
var ser = new XmlSerializer(typeof(Actions));
TextWriter w = new StringWriter();
ser.Serialize(w, actionList);
TextReader r = new StringReader(w.ToString());
Actions result = (Actions) ser.Deserialize(r);
}
}
Upvotes: 1