How do you avoid creating multiple instances of an object with XML Deserialization?
I've got a class that when serialized to XML looks like this (generalized for simplicity):
<root>
<resources>
<resource name="foo" anotherattribute="value">data</resource>
<resource name="bar" anotherattribute="value">more data</resource>
</resource>
<myobject name="objName">
<resource name="foo" />
</myobject>
</root>
When it's deserialized, I need the instance of resource
referenced in the property of the myobject
instance to be the same object created during the deserialization of the resources
collection. Also, if possible I don't want to have to output the full serialization of the resource
instance in myobject
, only the name.
Is there any way of doing this? Right now I'm considering resorting to having a separate stri开发者_开发问答ng property for serialization purposes that gets the relevant object from root
when the deserializer sets the property, but that means giving myobject
a reference to the root
that contains it, and I was hoping to avoid that coupling.
You can't do that with XmlSerializer
, because it doesn't handle object references.
If you don't have any constraint on the generated schema, you could use DataContractSerializer
, which also serializes to XML but supports references. To use DataContractSerializer
, each type must have a DataContract
attribute, and each member you want to serialize must have a DataMember
attribute :
[DataContract(Name = "root")]
public class root
{
[DataMember]
public List<resource> resources { get; set; }
[DataMember]
public myobject myobject { get; set; }
}
[DataContract]
public class myobject
{
[DataMember]
public string name { get; set; }
[DataMember]
public resource resource { get; set; }
}
[DataContract(Name = "resource", IsReference = true)]
public class resource
{
[DataMember]
public string name { get; set; }
[DataMember]
public string anotherattribute { get; set; }
[DataMember]
public string content { get; set; }
}
...
var serializer = new DataContractSerializer(typeof(root));
using (var xwriter = XmlWriter.Create(fileName))
{
serializer.WriteObject(xwriter, r);
}
Note the IsReference = true
for the resource
class: that's what makes the serializer handle this class by reference. In the generated XML, each resource
instance is only serialized once:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
<myobject>
<name>objName</name>
<resource z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<anotherattribute>value</anotherattribute>
<content>data</content>
<name>foo</name>
</resource>
</myobject>
<resources>
<resource z:Ref="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
<resource z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<anotherattribute>value</anotherattribute>
<content>more data</content>
<name>bar</name>
</resource>
</resources>
</root>
精彩评论