Hello folks.
I can really use some help here. What I am attempting to do is to create an XML serializer that can handle a class that has several derived subtypes. I already know the basics of doing this: I wrote
this blog entry to help me remember how.
But now, I am diving a little deeper and I've gotten my self stuck. Below is simplified sample of the XML I am working from:
<AssignmentDesk name="test desk"/>
<Extraction>
<Find>
...other instructions...
</Find>
<Find>
...other instructions...
</Find>
<Set>
...other instructions...
</Set>
</Extraction>
</AssignmentDesk>
And the classes to represent this look like:
[XmlRoot("AssignmentDesk")]
public class AssignmentDesk
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlElement("Extraction")]
public List<Extractor> Extractors { get; set; }
public static XmlAttributeOverrides GetXmlOverrides()
{
var attrs = new XmlAttributes();
foreach (Type type in
Assembly.GetAssembly(typeof(Instruction)).GetTypes()
.Where(myType => myType.IsClass && myType.IsSubclassOf(typeof(Instruction))))
{
var attr = new XmlArrayItemAttribute(type);
attrs.XmlArrayItems.Add(attr);
}
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Extractor), "SubInstructions", attrs);
return overrides;
}
}
public class Instruction
{
public List<Instruction> SubInstructions { get; set; }
}
public class Extractor : Instruction
{
}
public class Find : Instruction
{
}
public class Set : Instruction
{
}
Of course all these classes have other attributes and methods. I've stripped them down to the bare minimum here.
Now, the
Instruction class is meant represent a variety of different instructions (each represented by a classes derived from
Instruction). That is, I want to be able to create additional instructions (like
Find,
Set,
Put,
Finangle, or whatever) and have them be recognised by the XML serializer as just more
Instructions. To do this, I am using the
GetXmlOverrides() method on the
AssignmentDesk class to look for all classes derived from
Instructions and add them to the XML attribute overrides for the
SubInstructions property. I then use the returned overrides with the XML serializer
var serializer = new XmlSerializer(typeof(AssignementDesk), overrides, null, new XmlRootAttribute(root), null);
This is where I am running into problems. No matter what I try, when I deserialize the example XML I get
Extractors set to a list containing one
Extractor object (that's good). But that
Extractor object's
SubInstructions list i
s always empty.
I have tried changing the overrides.Add()
overrides.Add(typeof(AssignementDesk), "Extractors", attrs);
overrides.Add(typeof(AssignementDesk), "Extraction", attrs);
overrides.Add(typeof(Instruction), "SubInstructions", attrs);
etc.
I have tried changing the attribute type from
XmlArrayItemAttribute to
XmlElementAttribute. To be honest, I can't remember all the combinations I have tried. But none of them have worked.
Does anyone out there have an idea of what I may be doing wrong?
Note: You may be wondering why I don't just hard code the
[XmlArrayItem] attributes right above the
Extractors property (like I did to the
Instruments class in my blog entry). The reason is that I am hoping allow additional instructions (that is, classes derived from
Instruction) to be created outside of this class. I don't want to have to hard code each new instruction in
AssignmentDesk.
Yes, that is a lot of probably unnecessary work, but this is also a learning exercise for me: If I learn how to do this in my own home project, then perhaps I can, at some point long after I have retired, give some poor unsuspecting future code maintainer a massive migraine at 2 AM on a Saturday (a laudable goal, you must admit).
What I have tried:
Variations on changing the attribute types and member names used to create the XML overrides.
Checking the examples given by Microsoft (none of which seem to be quite what I am doing).
Considered trashing my computer and becoming a male stripper (definitely NOT a good idea)