C#无XmlAttributes泛型反序列化XML列表:对象值为空
解决无XmlAttributes的泛型XML属性反序列化问题
我懂你现在的困扰——你想做一个通用的XML反序列化工具,不用在实体类上加XmlAttributes,但现在虽然能拿到3个Item对象,所有属性都是默认值(0、null)对吧?
问题根源
你当前用的XmlSerializer默认行为是映射XML元素到类属性,但你的XML里的ItemId、ItemName这些都是XML节点的属性(就是<Item ItemId="1">里的键值对),所以默认的序列化器根本不会读取这些属性值,自然就填充默认值了。
通用解决方案:反射+XElement手动映射
既然要通用性,我们可以用反射来遍历XML节点的属性,然后手动映射到类的对应属性上,完全不需要加任何特性。
改进后的完整代码
private XDocument sourceData; // 假设这个已经被正确初始化 public List<T> GetObjectList<T>(string identifier) where T : class, new() { if (sourceData == null || string.IsNullOrEmpty(identifier)) return new List<T>(); // 直接遍历指定名称的节点,映射到对象 return sourceData.Descendants(identifier) .Select(MapXmlAttributesToObject<T>) .ToList(); } private T MapXmlAttributesToObject<T>(XElement element) where T : class, new() { var targetObj = new T(); var targetType = typeof(T); foreach (var xmlAttr in element.Attributes()) { // 找到类中匹配的属性(支持大小写不敏感,可根据需求调整) var targetProperty = targetType.GetProperty( xmlAttr.Name.LocalName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase ); if (targetProperty == null) continue; // 找不到对应属性就跳过 // 处理值转换,包括可空类型 try { object propertyValue; var nullableUnderlyingType = Nullable.GetUnderlyingType(targetProperty.PropertyType); // 处理可空类型+空字符串的情况 if (nullableUnderlyingType != null && string.IsNullOrEmpty(xmlAttr.Value)) { propertyValue = null; } else { // 转换值到目标类型(包括非可空类型) propertyValue = Convert.ChangeType( xmlAttr.Value, nullableUnderlyingType ?? targetProperty.PropertyType ); } targetProperty.SetValue(targetObj, propertyValue); } catch { // 转换失败时可以记录日志,这里简单跳过 continue; } } return targetObj; } // 你的Item类保持不变 public class Item { public int ItemId { get; set; } public string ItemName { get; set; } public int? Number { get; set;} public DateTime? Created { get; set; } }
调用方式
// 假设xml是你的XML字符串 sourceData = XDocument.Parse(xml); var itemList = GetObjectList<Item>("Item");
为什么这个方案能工作?
- 直接操作XElement:避免了把节点转成字符串再反序列化的低效操作,直接读取XML属性。
- 反射映射:通过反射动态找到类的属性,和XML属性名称匹配(支持大小写不敏感,适合不同XML的命名风格)。
- 处理可空类型:专门判断了可空类型(比如
int?、DateTime?)和空字符串的情况,确保空值能正确映射为null。 - 完全通用:不管你传入什么
T类型,只要属性名称和XML属性对应,就能自动完成映射,不需要加任何XmlAttribute或XmlElement特性。
验证结果
运行后你会得到正确的Item对象:
ItemId分别为1、2、3ItemName分别为TestName1、TestName2、TestName3Number分别为100、200、300Created均为null(因为XML里是空字符串)
内容的提问来源于stack exchange,提问作者WillC
相关产品推荐
相关产品推荐

