Xml序列化:使用元素的基类名称序列化从同一基类派生的自定义类的列表

本文关键字:序列化 基类 自定义 列表 派生 元素 Xml | 更新日期: 2023-09-27 18:02:14

编辑

我的假设错了。我回答自己,解释出了什么问题,以及我真正需要什么。


我在序列化不同自定义类的列表时遇到问题。它们中的每一个都继承自同一个基类,Xml文件应该显示具有基类名称的元素。

这就是我想要的Xml文件的样子:

<TestDataMap>
    <DataMap>
        <Item Key="BoolStatus">True</Item>
        <Item Key="IntStatus">77</Item>
    </DataMap>
</TestDataMap>

我的实际代码是由一个基类组成的:

    public class BaseItem
    {
        [XmlAttribute("Key")]
        public string Key { get; set; }
        [XmlText]
        public string Value { get; set; }
    }

和多个自定义类,例如:

    [XmlType("ItemBool")]
    public class ItemBool : BaseItem
    {
        public ItemBool()
        {
            base.Key = string.Empty;
            ValueBool = false;
        }
        [XmlIgnore]
        public bool ValueBool
        {
            get { return bool.Parse(base.Value); }
            set { base.Value = value.ToString(); }
        }
    }
    [XmlType("ItemInt")]
    public class ItemInt : BaseItem
    {
        public ItemInt()
        {
            base.Key = string.Empty;
            ValueInt = int.MinValue;
        }
        [XmlIgnore]
        public int ValueInt
        {
            get { return int.Parse(base.Value); }
            set { base.Value = value.ToString(); }
        }
    }

我需要将所有这些自定义类序列化为基类的列表,因此我完成了以下操作:

    [XmlRoot("TestDataMap")]
    public class TestDataMap
    {
        public TestDataMap()
        {
            DataMap = new List<BaseItem>();
        }
        // If I use the following I've got serialization exception...
        //[XmlArrayItem("Item", typeof(ItemBool))]
        //[XmlArrayItem("Item", typeof(ItemInt))]
        [XmlArray("DataMap")]
        [XmlArrayItem("Item", typeof(BaseItem))]
        public List<BaseItem> DataMap { get; set; }
    }

为了测试序列化,我使用了一个按钮事件:

    private void button1_Click(object sender, EventArgs e)
    {
        TestDataMap testDataMap = new TestDataMap();
        ItemBool itemBool = new ItemBool() { Key = "BoolStatus", ValueBool = true };
        ItemInt itemInt = new ItemInt() { Key = "IntStatus", ValueInt = 77 };
        testDataMap.DataMap.Add(itemBool);
        testDataMap.DataMap.Add(itemInt);
        TextWriter writer = new StreamWriter(@"c:'TempTest.xml");
        Type[] dataMapTypes = new Type[] { typeof(ItemBool), typeof(ItemInt) };
        XmlSerializer serializer = new XmlSerializer(typeof(TestDataMap), dataMapTypes);
        serializer.Serialize(writer, testDataMap);
        writer.Close();
    }

但我得到了这样的输出:

<TestDataMap>
    <DataMap>
        <Item Key="BoolStatus" xsi:type="ItemBool">True</Item>
        <Item Key="IntStatus" xsi:type="ItemInt">77</Item>
    </DataMap>
</TestDataMap>

包含我不想显示的xsi:type信息。。。我的代码出了什么问题?关于我必须更改什么才能获得问题开始时发布的Xml结构,有什么建议吗?

Xml序列化:使用元素的基类名称序列化从同一基类派生的自定义类的列表

当我问这个问题时,我过于关注输出xml文件的美学结果,而不关心要点:自定义类的xml序列化和随后的反序列化。即使我能够像最初发布的那样准确地获得xml元素,那么在反序列化过程中我也会遇到问题:在没有任何其他细节的情况下,反序列化程序如何从通用<Item>元素列表中知道哪个是<ItemBool>,哪个是<ItemInt>

考虑到这一点,我明白我所要求的不是我所需要的,也不是进行xml序列化的正确方法。

因此,我将上面发布的TestDataMap类更改为以下内容:

[XmlRoot("TestDataMap")]
public class TestDataMap
{
    public TestDataMap()
    {
        DataMap = new List<BaseItem>();
    }
    [XmlArray("DataMap")]
    [XmlArrayItem("ItemBool", typeof("ItemBool"))]
    [XmlArrayItem("ItemInt", typeof("ItemInt"))]
    public List<BaseItem> DataMap { get; set; }
}

要获得此xml输出:

<TestDataMap>
    <DataMap>
        <ItemBool Key="BoolStatus">True</ItemBool>
        <ItemInt Key="IntStatus">77</ItemInt>
    </DataMap>
</TestDataMap>

通过这种方式,反序列化器可以清楚地了解它必须如何反序列化每种类型的<Item>元素。