C#中HashSet的XML序列化失败问题求助
解决C# XmlSerializer反序列化分号分隔文本到HashSet的报错问题
错误原因
XmlSerializer默认处理HashSet<string>这类集合类型时,会期望XML中出现多个同名的子元素(比如多个<pnames>节点),但你的XML里是单个<pnames>节点包含分号分隔的文本内容。序列化器找不到预期的元素节点,就抛出了错误:期望状态‘Element’,却遇到名称为空、命名空间为空的‘Text’。
解决方案
方法一:通过中转属性实现文本与集合的转换
定义一个用于接收XML文本的中转属性,通过它的get和set方法完成分号分隔字符串与HashSet<string>的互相转换,同时忽略原集合属性的序列化:
public class Project { public int Id { get; set; } // 接收XML中的<pnames>文本内容 [XmlText] public string PnamesText { get => Pnames != null ? string.Join(";", Pnames) : string.Empty; set { if (!string.IsNullOrEmpty(value)) { Pnames = new HashSet<string>(value.Split(';', StringSplitOptions.RemoveEmptyEntries)); } else { Pnames = new HashSet<string>(); } } } // 实际业务使用的集合属性,标记为XmlIgnore避免序列化冲突 [XmlIgnore] public HashSet<string> Pnames { get; set; } = new HashSet<string>(); } public class Projects { [XmlElement("project")] public List<Project> ProjectList { get; set; } = new List<Project>(); }
方法二:实现IXmlSerializable接口自定义序列化逻辑
通过实现IXmlSerializable接口,手动控制XML的读取和写入流程,直接处理<pnames>的文本内容:
public class Project : IXmlSerializable { public int Id { get; set; } public HashSet<string> Pnames { get; set; } = new HashSet<string>(); public XmlSchema GetSchema() => null; public void ReadXml(XmlReader reader) { reader.ReadStartElement("project"); // 读取id节点内容 Id = int.Parse(reader.ReadElementContentAsString("id", "")); // 读取pnames节点文本并拆分转成HashSet string pnamesText = reader.ReadElementContentAsString("pnames", ""); if (!string.IsNullOrEmpty(pnamesText)) { Pnames = new HashSet<string>(pnamesText.Split(';', StringSplitOptions.RemoveEmptyEntries)); } reader.ReadEndElement(); } public void WriteXml(XmlWriter writer) { // 写入id节点 writer.WriteElementString("id", Id.ToString()); // 将HashSet合并成分号分隔字符串写入pnames节点 writer.WriteElementString("pnames", string.Join(";", Pnames)); } } public class Projects { [XmlElement("project")] public List<Project> ProjectList { get; set; } = new List<Project>(); }
总结
- 方法一实现简单,适合这种仅需字符串拆分/合并的场景;
- 方法二更灵活,适用于复杂XML结构的自定义序列化需求。
内容的提问来源于stack exchange,提问作者Techgeeks1
相关产品推荐
相关产品推荐

