如何序列化/反序列化从公共类继承并遵守相同接口的对象列表?

时间:2017-08-04 11:03:21

标签: c# xml serialization interface

我想获取一个从接口继承的对象列表,并将它们序列化为xml(JSON也可以接受)。这些对象中的每一个都从相同的抽象类继承并遵循相同的接口。

请参阅以下课程:

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
    }
}

//子类

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

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

在序列化/反序列化时,XmlSerializer类无法确定每个类的类型,我理解为什么,但我正在寻找解决问题的方法。

到目前为止,我唯一的成功是使用ExtendedXmlSerializer,它成功地序列化了数据如下:

<?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>

类型在type属性中指定,但ExtendededXmlSerializer无法反序列化xml,声明空引用异常。

以下是读取和写入数据的存储库代码。

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);
        }

我已经阅读了类似的堆栈溢出问题,但没有一个与我匹配(到目前为止)。

编辑:堆栈跟踪

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)

1 个答案:

答案 0 :(得分:3)

  

JSON也可以接受

我不确定你想要什么,但你可以保留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;
    }
}

输出:

Appreciative
2
2147483647
Unappreciative
4
-2147483648