C# 合并JsonPath与单对象转数组JsonConverter通用实现方案咨询
通用实现方案
1. 自定义映射特性
新增JsonPathPropertyAttribute特性,同时存储JSON路径和集合元素类型,替换原有JsonPropertyAttribute:
[AttributeUsage(AttributeTargets.Property)] public class JsonPathPropertyAttribute : Attribute { /// <summary> /// 对应JSON的Path路径 /// </summary> public string JsonPath { get; } /// <summary> /// 集合属性的元素类型,非集合属性可不传 /// </summary> public Type? CollectionElementType { get; } public JsonPathPropertyAttribute(string jsonPath, Type? collectionElementType = null) { JsonPath = jsonPath; CollectionElementType = collectionElementType; } }
2. 改造通用JsonPathConverter
整合单对象转集合逻辑,无需硬编码属性名,自动适配所有集合类型:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Reflection; using System.Collections; namespace GCRR { #nullable disable public class JsonPathConverter : JsonConverter { public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); object targetObj = Activator.CreateInstance(objectType); foreach (PropertyInfo prop in objectType.GetProperties() .Where(p => p.CanRead && p.CanWrite)) { // 读取自定义的JsonPath特性 var pathAtt = prop.GetCustomAttributes(true) .OfType<JsonPathPropertyAttribute>() .FirstOrDefault(); string jsonPath = pathAtt != null ? pathAtt.JsonPath : prop.Name; JToken token = jo.SelectToken(jsonPath); if (token == null || token.Type == JTokenType.Null) continue; // 处理集合属性单对象转数组逻辑 if (pathAtt?.CollectionElementType != null && prop.PropertyType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(prop.PropertyType) && token.Type == JTokenType.Object) { // 反序列化单个元素实例 var element = token.ToObject(pathAtt.CollectionElementType, serializer); // 创建对应集合类型的实例 var collection = Activator.CreateInstance(prop.PropertyType); // 调用集合的Add方法加入元素 var addMethod = prop.PropertyType.GetMethod("Add", new[] { pathAtt.CollectionElementType }); addMethod?.Invoke(collection, new[] { element }); // 赋值给属性 prop.SetValue(targetObj, collection, null); } else { // 普通属性直接反序列化 object value = token.ToObject(prop.PropertyType, serializer); prop.SetValue(targetObj, value, null); } } return targetObj; } public override bool CanConvert(Type objectType) { return false; } public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } }
3. 实体类适配
将原有JsonProperty替换为自定义的JsonPathProperty特性即可:
[JsonConverter(typeof(JsonPathConverter))] public class WaiverFileWaivers { [JsonPathProperty("Waiver", typeof(Waiver))] public List<Waiver>? Waivers { get; set; } } [JsonConverter(typeof(JsonPathConverter))] public class WaiverFileWaiver:Waiver { [JsonPathProperty("Particpants.WaiverParticipant", typeof(WaiverParticipant))] public List<WaiverParticipant>? WaiverParticipants { get; set; } }
适配说明
- 非集合属性使用时只需传JSON路径参数即可,不需要传集合元素类型
- 支持
List<T>、ICollection<T>等所有实现了Add方法的集合类型 - 原有反序列化代码不需要做任何修改,直接使用即可
内容的提问来源于stack exchange,提问作者Chris Ward
相关产品推荐
相关产品推荐

