Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XML Serialize generic list of serializable objects with abstract base class

Any good sample on how to serialize list of generic objects with abstract base class. Samples with non abstract base class are listed in XML Serialize generic list of serializable objects. My base class is similar to Microsoft.Build.Utilities.Task

like image 405
walter Avatar asked Feb 12 '12 06:02

walter


2 Answers

Another alternative is to use the XmlElementAttribute to move the list of known types to the generic list itself...

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

public abstract class Animal
{
    public int Weight { get; set; }    
}

public class Cat : Animal
{
    public int FurLength { get; set; }    
}

public class Fish : Animal
{
    public int ScalesCount { get; set; }    
}

public class AnimalFarm
{
    [XmlElement(typeof(Cat))]
    [XmlElement(typeof(Fish))]
    public List<Animal> Animals { get; set; }

    public AnimalFarm()
    {
        Animals = new List<Animal>();
    }
}

public class Program
{
    public static void Main()
    {
        AnimalFarm animalFarm = new AnimalFarm();
        animalFarm.Animals.Add(new Cat() { Weight = 4000, FurLength = 3 });
        animalFarm.Animals.Add(new Fish() { Weight = 200, ScalesCount = 99 });
        XmlSerializer serializer = new XmlSerializer(typeof(AnimalFarm));
        serializer.Serialize(Console.Out, animalFarm);
    }
}

... which will also result in a better looking XML output (without the ugly xsi:type attribute)...

<?xml version="1.0" encoding="ibm850"?>
<AnimalFarm xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Cat>
    <Weight>4000</Weight>
    <FurLength>3</FurLength>
  </Cat>
  <Fish>
    <Weight>200</Weight>
    <ScalesCount>99</ScalesCount>
  </Fish>
</AnimalFarm>
like image 73
Martin Avatar answered Sep 24 '22 06:09

Martin


It is often useful to have abstract classes with several derived types to allow use of strongly typed lists and the such.

For example you might have a DocumentFragment class which is abstract and two concrete classes called TextDocumentFragment and CommentDocumentFragment (this example from Willis).

This allows the creation of a List property which can contain objects only of those two types.

If you attempt to create a WebService that returns this list you get an error but this is easy to get around with the code below....

[Serializable()]
[System.Xml.Serialization.XmlInclude(typeof(TextDocumentFragment))]
[System.Xml.Serialization.XmlInclude(typeof(CommentDocumentFragment))]
public abstract class DocumentFragment {
...}

The XmlInclude attributes tell the class that it might be serialized to those two derived classes.

This generates an attribute in the DocumentFragment element specifying the actual type, as below.

<DocumentFragment xsi:type="TextDocumentFragment">

Any additonal properties specific to the derived class will also be included using this method.

like image 29
Dmitry Savy Avatar answered Sep 20 '22 06:09

Dmitry Savy