序列化具有相同类型名称的多态List

Jes*_*seF 7 .net c# polymorphism xmlserializer

我有一个对象,我正在尝试序列化为XML.在此对象内部是泛型类型(抽象类)的列表.此列表中的每个项可以是不同的类,但所有项都继承自抽象基类:

public abstract class animal
{
  public string type { get; set; }
}
public class cat:animal
{
  public string size { get; set; }
  public string furColor { get; set; }
}
public class fish:animal
{
  public string size { get; set; }
  public string scaleColor { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当我序列化列表时,我希望它看起来像这样:

<animal type="cat">
  <size>medium</size>
  <furColor>black</furColor>
</animal>
<animal type="fish">
  <size>small</size>
  <scaleColor>silver</scaleColor>
</animal>
Run Code Online (Sandbox Code Playgroud)

我尝试过简单的解决方案:

[XmlElement("Animal")]
public List<animal> Animals { get; set; }
Run Code Online (Sandbox Code Playgroud)

但它会引发错误,因为它不期望对象类型为"cat".将[XmlInclude]标记添加到基类,派生类或整个包含类(让我们称之为动物园)对此没有帮助.

我可以将typeof指定用于单个类:

[XmlElement("Animal", typeof(cat))]
public List<animal> Animals { get; set; }
Run Code Online (Sandbox Code Playgroud)

只要我只使用猫,这就可以正常使用.再一次,我在混合物中添加一条鱼,它会以相同的错误(不期待鱼)爆炸.

我可以添加多个typeof属性:

[XmlElement("Animal")]
[XmlElementAttribute(typeof(cat))]
[XmlElementAttribute(typeof(fish))]
public List<animal> Animals { get; set; }
Run Code Online (Sandbox Code Playgroud)

和这个编译,但忽略了元素名称,序列化对象作为<cat> </cat><fish> </fish>,分别,这是不可接受的.

我甚至尝试添加多个[XmlElement]标签:

[XmlElement("Animal", typeof(cat))]
[XmlElement("Animal", typeof(fish))]
public List<animal> Animals { get; set; }
Run Code Online (Sandbox Code Playgroud)

这个引发了一个不同的例外,这次对象"cat"和"fish"都在同一范围内使用"Animal"类型.

谁能想到解决这个问题的方法呢?

更新经过多一点挖掘后,我发现这个SO帖子建议将命名空间添加到基类:

[XmlRoot(Namespace="myNamespace")]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
public abstract class animal
Run Code Online (Sandbox Code Playgroud)

序列化产生以下结果:

<animal xsi:type="cat" type="cat">
  ...
</animal>
<animal xsi:type="fish" type="fish">
  ...
</animal>
Run Code Online (Sandbox Code Playgroud)

其中xsi:type ="cat"指的是类的名称,type ="cat"指的是在基类中创建的type属性(参见最顶层的示例).这非常接近我所需要的,我担心我可能只是在这里缺乏经验,但有没有办法摆脱xsi:type属性列表?

leg*_*ing 4

将 XmlInclude 属性添加到基类应该可以解决此序列化问题

    [Serializable]
    [XmlInclude(typeof(cat))]
    [XmlInclude(typeof(fish))]
    class animals
    {
         ....
    }

    public class cat:animals
    {
      public string size { get; set; }
      public string furColor { get; set; }
    }

    public class fish:animals
    {
      public string size { get; set; }
      public string scaleColor { get; set; }
    }
Run Code Online (Sandbox Code Playgroud)

更新

这是一个适合我的简单示例,我认为您实际上不需要 type 属性,因为您可以使用 typeof() 方法检索它。除非 type 属性有其他目的。

        List<animal> animals = new List<animal>();
        cat catofdoom = new cat();
        catofdoom.furColor = "brown";
        catofdoom.size = "10 pounds";
        animals.Add(catofdoom);

        fish fishofdoom = new fish();
        fishofdoom.scaleColor = "blue";
        fishofdoom.size = "12 inches";
        animals.Add(fishofdoom);


        try
        {
            XmlSerializer xs = new XmlSerializer(typeof(List<animal>));
            using (StreamWriter wr = new StreamWriter("animal.xml"))
            {
                xs.Serialize(wr, animals);
            }
        }
        catch (Exception e)
        {

            throw;
        }
Run Code Online (Sandbox Code Playgroud)

结果如下(非常基本的序列化,没有选项):

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfAnimal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <animal xsi:type="cat">
    <size>10 pounds</size>
    <furColor>brown</furColor>
  </animal>
  <animal xsi:type="fish">
    <size>12 inches</size>
    <scaleColor>blue</scaleColor>
  </animal>
</ArrayOfAnimal>
Run Code Online (Sandbox Code Playgroud)