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;
}
}