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

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

本文介绍了序列化具有相同类型名称的多态列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要序列化为XML的对象.在此对象内部的是一个通用类型(抽象类)的列表.列表中的每个项目都可以是一个不同的类,但是所有这些都是从抽象基类继承的:

I have an object I'm trying to serialize into XML. Inside this object is a list of a generic type (abstract class). Each item in this list could be a different class, but all are inheriting from the abstract base class:

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

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

When I serialize the list, I want it to look like this:

<animal type="cat">
  <size>medium</size>
  <furColor>black</furColor>
</animal>
<animal type="fish">
  <size>small</size>
  <scaleColor>silver</scaleColor>
</animal>

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

I've tried the simple solution:

[XmlElement("Animal")]
public List<animal> Animals { get; set; }

但是它引发了一个错误,因为它不期望对象类型为"cat".将[XmlInclude]标签添加到基类,派生类或整个包含类(我们称其为Zoo)都无济于事.

But it throws an error because it's not expecting the object type "cat." Adding the [XmlInclude] tag to either the base class, the derived class, or the whole containing class (let's call it zoo) does not help this.

我可以将typeof名称用于单个类:

I can use the typeof designation for a single class:

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

,只要我只使用猫,它就可以正常运行,如我所愿.同样,在我将鱼添加到混合物中的那一刻,它以相同的错误爆炸(不期望有鱼).

and this works properly, as I want it to, as long as I only use cats. Again, the minute I add a fish to the mix, it blows up with the same error (not expecting fish).

我可以添加多个typeof属性:

I can add multiple typeof attributes:

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

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

and this compiles, but ignores the element name, and serializes the objects as <cat> </cat> and <fish> </fish>, respectively, which is unacceptable.

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

I've even tried adding multiple [XmlElement] tags:

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

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

This one throws a different exception, this time that the objects "cat" and "fish" both use the type "Animal" in the same scope.

有人能想到解决这个问题的方法吗?

Can anyone think of a way around this?

更新经过进一步的挖掘,我发现了建议将命名空间添加到基类中:

UPDATE After a little more digging, I found This SO post which suggests adding the namespace to the base class:

[XmlRoot(Namespace="myNamespace")]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
public abstract class animal

序列化将产生以下内容:

Serializing this yields the following:

<animal xsi:type="cat" type="cat">
  ...
</animal>
<animal xsi:type="fish" type="fish">
  ...
</animal>

其中 xsi:type ="cat" 是指该类的名称,而 type ="cat" 是指在基类中创建的type属性(参见最上面的示例).这很接近我的需要,我担心这里可能只是经验不足,但是有没有办法摆脱xsi:type属性列表?

Where xsi:type="cat" refers to the name of the class, and type="cat" refers to the type attribute created within the base class (see the very top example). This is so close to what I need, and I fear I may just be suffering from inexperience here, but is there a way to get rid of the xsi:type attribute listing?

推荐答案

在您的基类中添加XmlInclude属性应该可以解决此序列化问题

Adding the XmlInclude Attribute to your base class should solve this serilazation issue

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

更新

这是一个对我有用的简短示例,您实际上不需要我认为的type属性,因为您可以使用typeof()方法进行检索.除非type属性有其他用途.

Here's a brief example that works on my side, you don't actually need the type attribute to my opinion because you can retrieve it with typeof() method. unless the type attribute had another purpose.

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

导致此结果(非常基本的序列化,没有选项):

results into this ( very basic serialization with no options ) :

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

这篇关于序列化具有相同类型名称的多态列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!