千古英雄同一叹,|

Yan之有理

园龄:6年8个月粉丝:0关注:0

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

这个扩展方法提供了四个功能:

  1. ToXml方法:将对象转换为XML字符串。可以传入可选的参数deserializeRootElementName和writeArrayAttribute,用于指定反序列化的根元素名称和是否写入数组属性。还可以通过options参数指定保存选项,以指定返回的XML字符串格式。

  2. FromXml方法:从XML字符串反序列化为指定类型的对象。在反序列化之前,该方法会修复可能导致反序列化问题的单个列表项。同时,还会将XML文档转换为JSON字符串,然后使用System.Text.Json进行反序列化。在反序列化之前,可以通过自定义的日期时间转换器进行自定义日期时间的转换。

  3. FindListPropertiesName私有方法:查找给定类型中所有List<>类型的属性名称。该方法使用递归来查找嵌套类型中的List<>属性。

  4. GetAllProperties和GetNestedProperties私有方法:用于获取给定类型及其嵌套类型的全部属性。这些方法使用递归来查找嵌套类型的属性。

使用这些扩展方法,您可以方便地在C#应用程序中进行对象和XML字符串之间的相互转换。

本文作者:Yan之有理

本文链接:https://www.cnblogs.com/1makesense/p/17938800

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Yan之有理  阅读(427)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起