C# 扩展方法 对象和XML字符串相互转换
public static class ObjectExtensions { // 扩展方法:将对象转换为XML字符串 public static string ToXml(this object? obj, string? deserializeRootElementName = null, bool writeArrayAttribute = false) => obj.ToXml(deserializeRootElementName, writeArrayAttribute, SaveOptions.DisableFormatting); // 扩展方法:将对象转换为XML字符串,同时提供保存选项 public static string ToXml(this object? obj, string? deserializeRootElementName, bool writeArrayAttribute, SaveOptions options) { // 如果对象为空,则返回空字符串 if (obj == null) { return string.Empty; } // 使用Json.NET将对象序列化为JSON,然后转换为XNode对象 var xDocument = Newtonsoft.Json.JsonConvert.DeserializeXNode(obj.ToJson(), deserializeRootElementName, writeArrayAttribute); // 如果XNode对象为空或转换失败,则返回空字符串;否则,以指定的格式选项返回XML字符串 return xDocument == null ? string.Empty : xDocument.ToString(options); } // 扩展方法:从XML字符串反序列化为指定类型的对象 public static T? FromXml<T>(this string xml) where T : class { // 如果XML字符串为空,则返回默认值 if (string.IsNullOrEmpty(xml)) { return default; } // 创建XML文档对象并加载XML字符串 XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xml); // 查找类型T中所有List属性的名称 var listProperties = FindListPropertiesName(typeof(T)); // 遍历所有List属性名,并确保XML中对应的元素有重复节点(用于修复可能导致反序列化问题的单个列表项) foreach (var propertyName in listProperties) { var xmlNodeList = xmlDoc.GetElementsByTagName(propertyName); if (xmlNodeList is { Count: 1 }) { var xmlNode = xmlNodeList[0]; if (xmlNode is { ParentNode.ParentNode: not null }) { xmlNode.ParentNode.AppendChild(xmlNode.CloneNode(true)); } } } // 将修改后的XML文档转换回JSON字符串 string jsonResult = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlDoc); // 设置JSON反序列化选项并添加自定义日期时间转换器 JsonSerializerOptions options = new JsonSerializerOptions(); options.Converters.Add(new DatetimeJsonConverter()); // 使用System.Text.Json从JSON字符串反序列化为指定类型的对象 var result = JsonSerializer.Deserialize<T>(jsonResult, options); // 返回反序列化的对象 return result; } // 私有辅助方法:查找给定类型中所有List<>类型的属性名称 private static List<string> FindListPropertiesName(Type type) { List<string> listProperties = new List<string>(); // 获取当前类型及其所有嵌套类型的属性信息 PropertyInfo[] properties = type.GetAllProperties(); foreach (PropertyInfo property in properties) { // 检查属性是否为List<>类型 if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) { string propertyName = property.Name; // 如果属性上有JsonPropertyName特性,则使用特性中的名称 var attribute = property.GetCustomAttribute<JsonPropertyNameAttribute>(); if (attribute != null) { propertyName = attribute.Name; } listProperties.Add(propertyName); } // 如果属性是类类型且不是字符串,则递归查找该类类型中的List<>属性 else if (property.PropertyType.IsClass && property.PropertyType != typeof(string)) { List<string> nestedListProperties = FindListPropertiesName(property.PropertyType); listProperties.AddRange(nestedListProperties); } } return listProperties; } // 私有辅助方法:获取当前类型及其嵌套类型的全部属性 private static PropertyInfo[] GetAllProperties(this Type type) { var properties = new List<PropertyInfo>(); foreach (var property in type.GetProperties()) { properties.Add(property); // 如果属性是类类型且不是字符串,则递归获取其内部的属性 if (property.PropertyType.IsClass && property.PropertyType != typeof(string)) { var nestedProperties = GetNestedProperties(property.PropertyType); properties.AddRange(nestedProperties); } } return properties.ToArray(); } // 私有辅助方法:递归获取嵌套类型的全部属性 private static List<PropertyInfo> GetNestedProperties(Type type) { var properties = new List<PropertyInfo>(); foreach (var property in type.GetProperties()) { properties.Add(property); // 如果属性是类类型且不是字符串,则继续查找该类类型内部的属性 if (property.PropertyType.IsClass && property.PropertyType != typeof(string)) { var nestedProperties = GetNestedProperties(property.PropertyType); properties.AddRange(nestedProperties); } } return properties; } }
这个扩展方法提供了四个功能:
-
ToXml方法:将对象转换为XML字符串。可以传入可选的参数deserializeRootElementName和writeArrayAttribute,用于指定反序列化的根元素名称和是否写入数组属性。还可以通过options参数指定保存选项,以指定返回的XML字符串格式。
-
FromXml方法:从XML字符串反序列化为指定类型的对象。在反序列化之前,该方法会修复可能导致反序列化问题的单个列表项。同时,还会将XML文档转换为JSON字符串,然后使用System.Text.Json进行反序列化。在反序列化之前,可以通过自定义的日期时间转换器进行自定义日期时间的转换。
-
FindListPropertiesName私有方法:查找给定类型中所有List<>类型的属性名称。该方法使用递归来查找嵌套类型中的List<>属性。
-
GetAllProperties和GetNestedProperties私有方法:用于获取给定类型及其嵌套类型的全部属性。这些方法使用递归来查找嵌套类型的属性。
使用这些扩展方法,您可以方便地在C#应用程序中进行对象和XML字符串之间的相互转换。
本文作者:Yan之有理
本文链接:https://www.cnblogs.com/1makesense/p/17938800
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?