.NET中使用XmlSerializer序列化基类列表为指定XML结构可行吗?
用XmlSerializer实现指定分组结构的Action子类列表XML序列化
可以实现,XmlSerializer完全支持处理继承关系的对象序列化,结合特性配置就能生成你需要的分组结构XML,具体步骤如下:
1. 标记继承关系
首先要在基类Action上通过[XmlInclude]特性声明所有需要序列化的子类,让XmlSerializer知晓这些类型的存在,避免序列化时抛出类型未知的异常:
[XmlInclude(typeof(AddCircle))] [XmlInclude(typeof(DeleteCircle))] [XmlInclude(typeof(AddTriangle))] [XmlInclude(typeof(DeleteTriangle))] public abstract class Action { public string Id { get; set; } } // 子类定义,可通过[XmlType]指定XML元素名 [XmlType("AddCircle")] public class AddCircle : Action { public int Radius { get; set; } } [XmlType("DeleteCircle")] public class DeleteCircle : Action { public string CircleId { get; set; } } [XmlType("AddTriangle")] public class AddTriangle : Action { public int SideLength { get; set; } } [XmlType("DeleteTriangle")] public class DeleteTriangle : Action { public string TriangleId { get; set; } }
2. 定义分组包装类
如果需要按特定规则(比如操作类型、形状类型)分组,要创建一个包装类,通过[XmlArray]指定分组的根节点名,再用[XmlArrayItem]绑定对应的子类和XML元素名:
示例1:按操作类型(Add/Delete)分组
[XmlRoot("ActionList")] public class ActionTypeGroupWrapper { [XmlArray("AddOperations")] [XmlArrayItem(typeof(AddCircle), ElementName = "AddCircle")] [XmlArrayItem(typeof(AddTriangle), ElementName = "AddTriangle")] public List<Action> AddActions { get; set; } = new List<Action>(); [XmlArray("DeleteOperations")] [XmlArrayItem(typeof(DeleteCircle), ElementName = "DeleteCircle")] [XmlArrayItem(typeof(DeleteTriangle), ElementName = "DeleteTriangle")] public List<Action> DeleteActions { get; set; } = new List<Action>(); }
示例2:按形状类型(Circle/Triangle)分组
[XmlRoot("ActionList")] public class ShapeTypeGroupWrapper { [XmlArray("CircleActions")] [XmlArrayItem(typeof(AddCircle), ElementName = "AddCircle")] [XmlArrayItem(typeof(DeleteCircle), ElementName = "DeleteCircle")] public List<Action> CircleActions { get; set; } = new List<Action>(); [XmlArray("TriangleActions")] [XmlArrayItem(typeof(AddTriangle), ElementName = "AddTriangle")] [XmlArrayItem(typeof(DeleteTriangle), ElementName = "DeleteTriangle")] public List<Action> TriangleActions { get; set; } = new List<Action>(); }
3. 执行序列化
将原始的List<Action>按分组规则拆分后放入包装类,再进行序列化:
// 构造测试数据 var allActions = new List<Action> { new AddCircle { Id = "A1", Radius = 10 }, new DeleteCircle { Id = "D1", CircleId = "Circle_001" }, new AddTriangle { Id = "A2", SideLength = 6 }, new DeleteTriangle { Id = "D2", TriangleId = "Triangle_001" } }; // 按操作类型分组 var groupWrapper = new ActionTypeGroupWrapper { AddActions = allActions.Where(a => a is AddCircle || a is AddTriangle).ToList(), DeleteActions = allActions.Where(a => a is DeleteCircle || a is DeleteTriangle).ToList() }; // 序列化 var serializer = new XmlSerializer(typeof(ActionTypeGroupWrapper)); using var stringWriter = new StringWriter(); serializer.Serialize(stringWriter, groupWrapper); string resultXml = stringWriter.ToString();
生成的XML结构大概如下:
<ActionList> <AddOperations> <AddCircle> <Id>A1</Id> <Radius>10</Radius> </AddCircle> <AddTriangle> <Id>A2</Id> <SideLength>6</SideLength> </AddTriangle> </AddOperations> <DeleteOperations> <DeleteCircle> <Id>D1</Id> <CircleId>Circle_001</CircleId> </DeleteCircle> <DeleteTriangle> <Id>D2</Id> <TriangleId>Triangle_001</TriangleId> </DeleteTriangle> </DeleteOperations> </ActionList>
注意事项
- 必须显式声明所有需要序列化的子类,无论是通过基类的
[XmlInclude],还是在创建XmlSerializer实例时传入类型数组。 - 如果不需要分组,直接序列化
List<Action>也可以,但生成的XML是无分组的平级列表,所有子类元素会直接放在根节点下。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

