【问题标题】:Xml serialization: serialize list of custom classes, derived from the same base class, using base class name for elementsxml序列化:序列化自定义类列表,派生自同一个基类,元素使用基类名
【发布时间】:2014-06-24 14:12:42
【问题描述】:

编辑

我的假设有误。我已经回答自己解释出了什么问题以及我真正需要什么。


序列化不同自定义类的列表时遇到问题。它们中的每一个都继承自同一个基类,并且 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 结构的任何建议?

【问题讨论】:

  • 好吧,删除[XmlType("ItemBool")] 将删除xsi:type="ItemBool";但这也意味着它不会在没有工作的情况下反序列化。
  • @MichaelPerrenoud - 我已尝试按照您的建议删除[XmlType("ItemBool")],但xsi:type 部分仍然存在。是否有一些我需要显式隐式属性?

标签: c# xml list xml-serialization derived-class


【解决方案1】:

当我问这个问题时,我过于关注输出xml文件的审美结果,而不是关心重点:自定义类的xml序列化和后续的反序列化。 即使我能够完全获得我最初发布的xml元素,那么我在反序列化过程中也会遇到问题:反序列化器如何从通用&lt;Item&gt;元素列表中知道哪个是&lt;ItemBool&gt;,哪一个是&lt;ItemInt&gt;,没有任何其他细节?

想到这里,我明白我问的不是我需要的,也不是做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>

通过这种方式,反序列化器很清楚它必须如何反序列化每种类型的&lt;Item&gt; 元素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多