基于OOP多态性实现两类XML反序列化时隐藏基类异常的解决
解决XML多态反序列化中基类属性隐藏的异常问题
我明白你遇到的头疼问题——想用virtual+new的多态思路处理两类结构相似的XML反序列化,结果却因为基类属性的冲突抛出了异常。咱们一步步来把这个问题解决掉:
问题场景回顾
你手头有两类XML,核心差异集中在<MSGDATA>节点的内部结构:
TYPE 1 XML
<MESSAGE> <DOCUMENT> <MSGHDR> <TIME_STAMP>2020010100:00:00.000</TIME_STAMP> <MESSAGE_NAME>1</MESSAGE_NAME> </MSGHDR> <MSGDATA> <ITEMSTYPE_1> <ITEMTYPE_1> <NAME_OF_TYPE_1>TYPE1_AAAA</NAME_OF_TYPE_1> </ITEMTYPE_1> <ITEMTYPE_1> <NAME_OF_TYPE_1>TYPE1_BBBB</NAME_OF_TYPE_1> </ITEMTYPE_1> </ITEMSTYPE_1> </MSGDATA> </DOCUMENT> <DOCUMENT> <MSGHDR> <TIME_STAMP>2020010100:00:00.000</TIME_STAMP> <MESSAGE_NAME>2</MESSAGE_NAME> </MSGHDR> <MSGDATA> <ITEMSTYPE_1> <ITEMTYPE_1> <NAME_OF_TYPE_1>TYPE1_EEEEEE</NAME_OF_TYPE_1> </ITEMTYPE_1> <ITEMTYPE_1> <NAME_OF_TYPE_1>TYPE1_FFFFF</NAME_OF_TYPE_1> </ITEMTYPE_1> </ITEMSTYPE_1> </MSGDATA> </DOCUMENT> </MESSAGE>
TYPE 2 XML
<MESSAGE> <DOCUMENT> <MSGHDR> <TIME_STAMP>2020010100:00:00.000</TIME_STAMP> <MESSAGE_NAME>1</MESSAGE_NAME> </MSGHDR> <MSGDATA> <ITEMSTYPE_2> <ITEMTYPE_2> <NAME_OF_TYPE_2>TYPE2_CCCC</NAME_OF_TYPE_2> </ITEMTYPE_2> <ITEMTYPE_2> <NAME_OF_TYPE_2>TYPE2_DDDD</NAME_OF_TYPE_2> </ITEMTYPE_2> </ITEMSTYPE_2> </MSGDATA> </DOCUMENT> </MESSAGE>
你的核心思路是通过抽象基类+子类继承,用new关键字覆盖基类的Documents属性来适配不同的DOCUMENT类型,但反序列化时直接触发了隐藏基类的异常。
问题根源
XmlSerializer会扫描类的所有继承层级属性,哪怕你用new关键字“隐藏”了基类属性,只要基类的属性没标记[XmlIgnore],序列化器就会同时识别基类和子类的Documents属性,直接导致属性重复的冲突。
解决方案
在抽象基类的虚拟属性上添加[XmlIgnore],明确告诉序列化器忽略基类的这个属性,只处理子类中用new重新定义的属性。这样既保留了多态的结构,又能让序列化器正常工作。
修正后的完整代码
基类与TYPE1相关实现
[XmlRoot("MESSAGE")] public abstract class ItemMessage { [XmlIgnore] // 关键:标记为XmlIgnore,避免序列化器识别该属性 public virtual List<ItemDocument> Documents { get; set; } } [XmlRoot("MESSAGE")] public class Item_1_Message : ItemMessage { [XmlElement("DOCUMENT")] // 子类重新定义属性,绑定XML元素名 public new List<Type_1_ItemDocument> Documents { get; set; } } [XmlRoot(ElementName="MSGHDR")] public class MsgHeader { [XmlElement("TIME_STAMP")] public string strTimeStamp { get; set; } [XmlElement("MESSAGE_NAME")] public string MessageName { get; set; } } [XmlRoot("DOCUMENT")] public abstract class ItemDocument { [XmlElement("MSGHDR")] public MsgHeader MsgHeader { get; set; } } // TYPE1 专属数据类 public class Type_1_ItemDocument : ItemDocument { [XmlElement("MSGDATA")] public Type_1_ItemData itemData { get; set; } } [XmlRoot(ElementName = "MSGDATA")] public class Type_1_ItemData { [XmlElement(ElementName = "ITEMSTYPE_1")] public ItemsType_1 itemstype1 { get; set; } } [XmlRoot(ElementName = "ITEMSTYPE_1")] public class ItemsType_1 { [XmlElement("ITEMTYPE_1")] public List<Item1> items { get; set; } } [XmlRoot(ElementName = "ITEMTYPE_1")] public class Item1 { [XmlElement(ElementName = "NAME_OF_TYPE_1")] [JsonProperty("Name")] public string name { get; set; } }
TYPE2相关实现(补充完整供参考)
[XmlRoot("MESSAGE")] public class Item_2_Message : ItemMessage { [XmlElement("DOCUMENT")] public new List<Type_2_ItemDocument> Documents { get; set; } } public class Type_2_ItemDocument : ItemDocument { [XmlElement("MSGDATA")] public Type_2_ItemData itemData { get; set; } } [XmlRoot(ElementName = "MSGDATA")] public class Type_2_ItemData { [XmlElement(ElementName = "ITEMSTYPE_2")] public ItemsType_2 itemstype2 { get; set; } } [XmlRoot(ElementName = "ITEMSTYPE_2")] public class ItemsType_2 { [XmlElement("ITEMTYPE_2")] public List<Item2> items { get; set; } } [XmlRoot(ElementName = "ITEMTYPE_2")] public class Item2 { [XmlElement(ElementName = "NAME_OF_TYPE_2")] [JsonProperty("Name")] public string name { get; set; } }
反序列化验证
现在你可以正常执行以下代码反序列化TYPE1 XML:
XmlSerializer xmls = new XmlSerializer(typeof(Item_1_Message)); var result = xmls.Deserialize(new StringReader(xmlText));
处理TYPE2 XML时,只需要把typeof(Item_1_Message)替换为typeof(Item_2_Message)即可。
额外说明
这种方案既保留了OOP多态的优势(你可以用ItemMessage作为统一基类处理不同消息),又完美解决了XmlSerializer的属性冲突问题。后续如果新增其他类型的XML,只需要继承ItemMessage和ItemDocument,重新定义对应的属性和数据类即可,扩展性拉满。
内容的提问来源于stack exchange,提问作者Guy E
相关产品推荐
相关产品推荐

