Bob Bob - 2 months ago 9
C# Question

How to serialize the base class with derived classes

.

Hello,

I have this sample code :

public class Vehicule
{
public string Name { get; set; }
public Brand Brand { get; set; }
}
public class Car : Vehicule
{
public string Matriculation { get; set; }
}



public class Brand
{
public string Name { get; set; }
}
public class Renault : Brand
{
public string Information { get; set; }
}


If I create this instance :

var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };


When I serialize this object like that :

var serializer = new XmlSerializer(typeof(Car), new Type[] { typeof(Renault)});
serializer.Serialize(wr, car);


I obtain this :

<?xml version="1.0" encoding="utf-8"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Clio</Name>
<Brand xsi:type="Renault">
<Name>Renault</Name>
<Information>Contact Infos</Information>
</Brand>
<Matriculation>XXX-XXX</Matriculation>
</Car>


But, in my project, I don't have to have informations on derived classes, I would like only elements of base classes from this instance like this :

var serializer = new XmlSerializer(typeof(Vehicule));
serializer.Serialize(wr, car);


The Xml :

<?xml version="1.0" encoding="utf-8"?>
<Vehicule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Clio</Name>
<Brand>
<Name>Renault</Name>
</Brand>
</Vehicule>


Can you please, help me to obtain the good Xml (only with base type Vehicule and Brand) ?

Many thanks

Answer

You can't magically serialize a derived class as it's base because

"...Serialization checks type of instance by calling Object.getType() method. This method always returns the exact type of object."

http://bytes.com/topic/net/answers/809946-how-force-serialize-base-type

The solution here, if you really need to only serialize the base class is to implement the IXmlSerializable interface and create your own custom serializer.

IXmlSerializable: http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx

One more thought. If you can work around the limitation of outputting the extra XML elements, you are able to serialize the derived class using only the base object by either 1) using XmlIncludeAttributes on the base class to tell it which types to expect or 2) using the XmlSerializer constructor overload that takes a list of types.

Edit: After thinking about this a little more, a workaround would be that you would add a Clone() method onto your base object, then serialize the clone of the base.

LinqPad code:

public class Vehicule
{
    public string Name { get; set; }
    public Brand Brand { get; set; }

    public Vehicule Clone()
    {
        return new Vehicule { Name = this.Name, Brand = new Brand { Name = this.Brand.Name } };
    }
}
public class Car : Vehicule
{
    public string Matriculation { get; set; }
}



public class Brand
{
    public string Name { get; set; }
}
public class Renault : Brand
{
    public string Information { get; set; }
}

void Main()
{   
    var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
    var vehicle = car as Vehicule;

    var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicule));

    XmlWriterSettings settings = new XmlWriterSettings
    {
        Encoding = new UnicodeEncoding(false, false),
        Indent = false,
        OmitXmlDeclaration = false
    };

    using(StringWriter textWriter = new StringWriter()) {
        using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
            serializer.Serialize(xmlWriter, vehicle.Clone());
        }
        textWriter.ToString().Dump();
    }
}