You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 23:24:10