简体   繁体   中英

How is it possible to serialize/deserialize a list of objects that inherit from a common class and adhere to the same Interface?

I would like to take a list of objects that inherit from an interface and serialize them to xml(JSON also acceptable). Each of these objects inherit from the same abstract class and adhere to the same interface.

Please see the classes below:

public abstract class Item
{
    public string Name { get; set; }
    public int SellIn { get; set; }
    public int Quality { get; set; }

    public Item(string name, int sellIn, int quality)
    {
        Name = name;
        SellIn = sellIn;
        Quality = quality;
    }

    public virtual void UpdateQuality()
    {
        //Default Behaviour
    }
}

//Sub classes

public class Appreciative : Item, IItem
{
    public Appreciative(string name, int sellIn, int quality) : base(name, sellIn, quality)
    {}

    public override void UpdateQuality()
    {
        //Sub class behaviour
    }
}

The XmlSerializer class cannot determine the type of each class when serializing/deserializing, I understand why but I am looking for a way around the issue.

The only success I have had so far is in using the ExtendedXmlSerializer which has successfully serialized the data as follows:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfIItem>
 <Depreciative type="CodingChallenge3.Internals.Items.Depreciative">
    <Name>+5 Dexterity Vest</Name>
    <SellIn>9</SellIn>
    <Quality>18</Quality>
 </Depreciative>
 <Appreciative type="CodingChallenge3.Internals.Items.Appreciative">
    <Name>Aged Brie</Name>
    <SellIn>1</SellIn>
    <Quality>1</Quality>
 </Appreciative>
 <Depreciative type="CodingChallenge3.Internals.Items.Depreciative">
    <Name>Elixir of the Mongoose</Name>
    <SellIn>4</SellIn>
    <Quality>5</Quality>
 </Depreciative>
 <Fixed type="CodingChallenge3.Internals.Items.Fixed">
    <Name>Sulfuras, Hand of Ragnaros</Name>
    <SellIn>0</SellIn>
    <Quality>80</Quality>
 </Fixed>
 <TicketEvent type="CodingChallenge3.Internals.Items.TicketEvent">
    <Name>Backstage passes to a TAFKAL80ETC concert</Name>
    <SellIn>14</SellIn>
    <Quality>20</Quality>
 </TicketEvent>
 <Depreciative type="CodingChallenge3.Internals.Items.Depreciative">
    <Name>Conjured Mana Cake</Name>
    <SellIn>2</SellIn>
    <Quality>4</Quality>
 </Depreciative>
</ArrayOfIItem>

The types are specified in the type attribute but the ExtendededXmlSerializer fails to deserialize the xml, stating a null reference exception.

Here is the repository code that reads and writes the data.

var serializedData = new ExtendedXmlSerializer().Serialize(inventory);
        System.IO.File.WriteAllText(PATH, serializedData);

var inventory = new List<IItem>();
        if (System.IO.File.Exists(PATH))
        {
            var serializedData = System.IO.File.ReadAllText(PATH);
            inventory = new ExtendedXmlSerializer().Deserialize<List<IItem>>(serializedData);
        }

I have read similar issues on stack overflow but none that match mine(thus far).

EDIT: The stacktrace

at ExtendedXmlSerialization.ExtendedXmlSerializer.ReadXml(XElement currentNode, TypeDefinition type, Object instance)
at ExtendedXmlSerialization.ExtendedXmlSerializer.ReadXmlArray(XElement currentNode, TypeDefinition type, Object instance)
at ExtendedXmlSerialization.ExtendedXmlSerializer.ReadXml(XElement currentNode, TypeDefinition type, Object instance)
at ExtendedXmlSerialization.ExtendedXmlSerializer.Deserialize(String xml, Type type)
at ExtendedXmlSerialization.ExtendedXmlSerializer.Deserialize[T](String xml)

JSON also acceptable

I'm not exactly sure what you want, but you can preserve types in Json.Net:

using Newtonsoft.Json;

void Main()
{
    var list = new List<IItem> { 
        new Appreciative("testing", 1, 2),
        new Unappreciative("testing", 3, 4)
    };

    var json = JsonConvert.SerializeObject(list, 
           new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });

    var newList = JsonConvert.DeserializeObject<List<IItem>>(json, 
           new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects });

    foreach (var item in newList) {
        Console.WriteLine(item.GetType().Name);
        Console.WriteLine(item.Quality);
        item.UpdateQuality();
        Console.WriteLine(item.Quality);
    }
}

public interface IItem
{
    string Name { get; set; }
    int SellIn { get; set; }
    int Quality { get; set; }
    void UpdateQuality();
}

public abstract class Item : IItem
{
    public string Name { get; set; }
    public int SellIn { get; set; }
    public int Quality { get; set; }

    public Item(string name, int sellIn, int quality)
    {
        Name = name;
        SellIn = sellIn;
        Quality = quality;
    }

    public virtual void UpdateQuality()
    {
        //Default Behaviour
    }
}

//Sub classes

public class Appreciative : Item
{
    public Appreciative(string name, int sellIn, int quality) 
                      : base(name, sellIn, quality)
    {}

    public override void UpdateQuality()
    {
        Quality = int.MaxValue;
    }
}

public class Unappreciative : Item
{
    public Unappreciative(string name, int sellIn, int quality) 
                        : base(name, sellIn, quality)
    {}

    public override void UpdateQuality()
    {
        Quality = int.MinValue;
    }
}

Output:

Appreciative
2
2147483647
Unappreciative
4
-2147483648

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