XML序列化/反序列化:如何为同一类不同实例的属性设置不同别名
实现方案
有两种稳定可行的实现方式,无需自定义完整的XmlSerializer,使用.NET XML序列化框架原生能力即可满足需求:
方案1:代理属性适配(轻量无侵入)
通过新增序列化专用代理属性+DTO的方式实现,不改动原有业务逻辑,代码易维护:
步骤1:新增DataB场景下的ClassA适配类
public class ClassADtoForDataB { [XmlElement("Name")] public string Code { get; set; } [XmlElement("Text")] public string Value { get; set; } // 隐式转换实现与原ClassA的无缝互转 public static implicit operator ClassADtoForDataB(ClassA source) { return new ClassADtoForDataB { Code = source.Code, Value = source.Value }; } public static implicit operator ClassA(ClassADtoForDataB source) { return new ClassA { Code = source.Code, Value = source.Value }; } }
步骤2:修改Foo类的序列化配置
public class Foo { // 原业务属性标记为忽略序列化 [XmlIgnore] public List<ClassA> DataA { get; set; } [XmlIgnore] public List<ClassA> DataB { get; set; } // 序列化专用属性 [XmlArray("DataA")] [XmlArrayItem("ClassA")] public List<ClassA> SerializeDataA { get => DataA; set => DataA = value; } [XmlArray("DataB")] [XmlArrayItem("ClassA")] public List<ClassADtoForDataB> SerializeDataB { get => DataB?.Select(x => (ClassADtoForDataB)x).ToList(); set => DataB = value?.Select(x => (ClassA)x).ToList(); } }
方案2:实现IXmlSerializable接口(完全自定义序列化逻辑)
如果不希望新增额外类,可直接让Foo类实现IXmlSerializable接口,自主控制序列化/反序列化的全流程,输出XML完全符合预期:
using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; public class Foo : IXmlSerializable { public List<ClassA> DataA { get; set; } public List<ClassA> DataB { get; set; } public XmlSchema GetSchema() => null; public void ReadXml(XmlReader reader) { reader.ReadStartElement(nameof(Foo)); // 反序列化DataA节点 reader.ReadStartElement(nameof(DataA)); DataA = new List<ClassA>(); while (reader.NodeType == XmlNodeType.Element && reader.Name == nameof(ClassA)) { var item = new ClassA(); reader.ReadStartElement(nameof(ClassA)); item.Code = reader.ReadElementContentAsString(nameof(Code), string.Empty); item.Value = reader.ReadElementContentAsString(nameof(Value), string.Empty); reader.ReadEndElement(); DataA.Add(item); } reader.ReadEndElement(); // 反序列化DataB节点 reader.ReadStartElement(nameof(DataB)); DataB = new List<ClassA>(); while (reader.NodeType == XmlNodeType.Element && reader.Name == nameof(ClassA)) { var item = new ClassA(); reader.ReadStartElement(nameof(ClassA)); item.Code = reader.ReadElementContentAsString("Name", string.Empty); item.Value = reader.ReadElementContentAsString("Text", string.Empty); reader.ReadEndElement(); DataB.Add(item); } reader.ReadEndElement(); reader.ReadEndElement(); } public void WriteXml(XmlWriter writer) { // 序列化DataA节点 writer.WriteStartElement(nameof(DataA)); foreach (var item in DataA ?? Enumerable.Empty<ClassA>()) { writer.WriteStartElement(nameof(ClassA)); writer.WriteElementString(nameof(Code), item.Code); writer.WriteElementString(nameof(Value), item.Value); writer.WriteEndElement(); } writer.WriteEndElement(); // 序列化DataB节点 writer.WriteStartElement(nameof(DataB)); foreach (var item in DataB ?? Enumerable.Empty<ClassA>()) { writer.WriteStartElement(nameof(ClassA)); writer.WriteElementString("Name", item.Code); writer.WriteElementString("Text", item.Value); writer.WriteEndElement(); } writer.WriteEndElement(); } }
说明
XmlAttributeOverrides无法实现该需求的原因是其配置是针对类型全局生效的,无法为同一个类型在不同父级属性下配置不同的映射规则,上述两种方案都可以完美规避这个问题。
内容的提问来源于stack exchange,提问作者BahaBulle
相关产品推荐
相关产品推荐

