Control serialization of derived type
Given a type such as:
public class FooList : List<Foo>
{
public string SomeMessage { get; set; }
}
How can I get the SomeMessage
property to be serialized along with the collection without overriding serialization itself?
What I am getting is:
<FooList>
<Foo />
<Foo />
<Foo />
</FooList>
and what I want is:
<FooList>
<SomeMessage />
<Foo />
<Foo />
&l开发者_如何学编程t;Foo />
</FooList>
For whatever reason, (I think it is because the serialization being used for the generic list doesn't see the new property) it isn't being written out.
In case it matters, here is what I am using to serialize it.
FooList content = new FooList();
content.SomeMessage="this is a test";
//add foos
using (TextWriter writer = new StreamWriter("C:\\foos.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(FooList));
serializer.Serialize(writer, content);
}
When the XmlSerializer
serializes a collection, it only takes the items of the collection into account. Any extra property declared in the class is ignored. You will either have to implement IXmlSerializable
to provide your own serialization logic, or change the design of your class.
You could do something like that:
[XmlRoot("FooList")]
public class FooListContainer
{
public string SomeMessage { get; set; }
[XmlElement("Foo")]
public List<Foo> Foos { get; set; }
}
If you need to implement the XmlChoiceIdentifierAttribute
, the XmlSerializer will be able to handle your requirements properly.
More info on the topic here:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlchoiceidentifierattribute.aspx
Sample code:
[System.Xml.Serialization.XmlElementAttribute("myType1", typeof(string))]
[System.Xml.Serialization.XmlElementAttribute("myType2", typeof(string))]
[System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
public string[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
If you prefer to generate the serializable class via xsd.exe
, then the xsd schema should look something like this (notice the xs:choice
tag):
<xs:complexType name="rowElement">
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element name="myType1" type="xs:string"/>
<xs:element name="myType2" type="xs:string"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
HTH...
When deriving from a collection class the XmlSeralizier
will only serialize the elements in the collection. One way to work around this is to create a class that wraps the collection and SomeMessage
and have that serialized.
[XmlRoot("FooList")]
public class CollectionWrapper
{
[XmlElement]
public List<Foo> Items { get; set; }
public string SomeMessage { get; set; }
}
Then you could to this:
CollectionWrapper cw = new CollectionWrapper();
cw.Items = new List<Foo>();
cw.Items.Add(foo1);
cw.Items.Add(foo2);
cw.SomeMessage = "this is a test";
using (TextWriter writer = new StreamWriter("C:\\foos.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(CollectionWrapper));
serializer.Serialize(writer, cw);
}
A detailed discussion is available here.
Try decorating SomeMessage with an [XMLElement] attribute, to force the XMLSerializer to include it.
精彩评论