简体   繁体   中英

XmlInclude to (De)Serialize Inherited Types in Separate Assemblies

I have this scenario:

namespace MyApp.Animals
{
  public class Dog : MyApp.Categories.Canine
  ...

So I'm trying to serialize/ deserialize the dog class. Unfortunately I can't use the [XmlInclude] attribute, because by adding it to the parent class (MyApp.Categories.Canine), I need to add a reference to the assembly in which the parent class exists (MyApp.Animals).. however the child class is already referencing the parent class due to the inheritance... so we have a circular reference.

is there any best practice way of achieving this? I can work around it by manually serializing/deserializing the properties that exist on the parent class, and just doing the serialization on the child, but that's not very elegant.

Hoping for some better tips..

UPDATE: Adding to the example in response to John's comment below...

I dont have a full code example (the code i'm working with is massive and complicated), but the issue is that some of the properties that should de/serialise to/from the xml are contained in the parent class, which is in a different assembly to the child class.

Adding the XmlElement attributes to the parent class doesn't work as we are actually doing the de/serialisation on the child class, so it doesnt iterate up to the parent. And we can't do it on the parent because we can't add a reference to the child (as the child is already referencing the parent), so the de/serialiser won't know which child to act on.

To add an extra level of complexity, the object that i have the problem with is actually being de/serialised as part of a greater serialisation, by the following property of a parent object:

    [XmlElement("ShippingAddress")]
    public Location ShippingAddress
    {
        get { return _shippingAddress; }
        set { _shippingAddress = value; }
    }

The problem is that the Location type here is the child location type. So only the properties in the child type are getting de/serialised... all the properties in the parent type (also called Location, but in a differnet namespace) are not.

does that make it any clearer?

XmlSerializer has a constructor that takes in an array of types called "extraTypes". Types in this array will be available during serialization and deserialization just as if you had added XmlInclude attributes.

var serializer = new XmlSerializer(typeof(Canine), new Type[] { typeof(Dog) });

Update: That approach works if your Xml includes a xsi:type attribute when the type is different from what was declared on the root object. It sounds like you might want to simply always deserialize that property as a different type. In that case, you can use XmlAttributeOverrides to replace the metadata on the original types. Constructing the XmlSerializer like this:

var overrides = new XmlAttributeOverrides();
var xmlAttributes = new XmlAttributes();
xmlAttributes.XmlElements.Add(new XmlElementAttribute("ShippingAddress", typeof(ITSM.Location)));
overrides.Add(typeof(Order), "Location", xmlAttributes);
var ser = new XmlSerializer(typeof(Order), overrides);

will have the same effect as replacing the attributes on the Order.Location property with:

[XmlElement("ShippingAddress", typeof(ITSM.Location))]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM