views:

179

answers:

1

The Goal:

XML serialize an object that contains a list of objects of that and its derived types. The resulting XML should not use the xsi:type attribute to describe the type, to wit the names of the serialized XML elements would be an assigned name specific to the derived type, not always that of the base class, which is the default behavior.

The Attempt:

After exploring IXmlSerializable and IXmlSerializable with eerie XmlSchemaProvider methods and voodoo reflection to return specialized schemas and an XmlQualifiedName over the course of days, I found I was able to use the simple [XmlElement] attribute to accomplish the goal... almost.

The Problem:

Overridden properties appear twice when serializing. The exception reads "The XML element 'overriddenProperty' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element." I attempted using a *Specified property (see code), but it didn't work.

Sample Code:

Class Declaration

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

[XmlInclude(typeof(DerivedClass))]
public class BaseClass
{
    public BaseClass() { }

    [XmlAttribute("virt")]
    public virtual string Virtual
    {
        get;
        set;
    }
    [XmlIgnore]
    public bool VirtualSpecified
    {
        get { return (this is BaseClass); }
        set { }
    }

    [XmlElement(ElementName = "B", Type = typeof(BaseClass), IsNullable = false)]
    [XmlElement(ElementName = "D", Type = typeof(DerivedClass), IsNullable = false)]
    public List<BaseClass> Children
    {
        get;
        set;
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass() { }

    [XmlAttribute("virt")]
    public override string Virtual
    {
        get { return "always return spackle"; }
        set { }
    }
}

Driver:

BaseClass baseClass = new BaseClass() { 
    Children = new List<BaseClass>()
};
BaseClass baseClass2 = new BaseClass(){};
DerivedClass derivedClass1 = new DerivedClass() { 
    Children = new List<BaseClass>()
};
DerivedClass derivedClass2 = new DerivedClass()
{
    Children = new List<BaseClass>()
};

baseClass.Children.Add(derivedClass1);
baseClass.Children.Add(derivedClass2);
derivedClass1.Children.Add(baseClass2);

I've been wrestling with this on and off for weeks and can't find the answer anywhere.

+1  A: 

Found it.

The Solution:

Decorate the overridden properties with the [XmlIgnore] attribute. The correct virtual value is still serialized.

Class Declaration

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

[XmlInclude(typeof(DerivedClass))]
public class BaseClass
{
    public BaseClass() { }

    [XmlAttribute("virt")]
    public virtual string Virtual
    {
        get;
        set;
    }

    [XmlElement(ElementName = "B", Type = typeof(BaseClass), IsNullable = false)]
    [XmlElement(ElementName = "D", Type = typeof(DerivedClass), IsNullable = false)]
    public List<BaseClass> Children
    {
        get;
        set;
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass() { }

    [XmlAttribute("virt")]
    [XmlIgnore]
    public override string Virtual
    {
        get { return "always return spackle"; }
        set { }
    }
}
Laramie