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

C#中如何序列化任意类型对象时仅保留嵌套列表的首尾元素到JSON

解决方案:自定义ContractResolver处理List序列化

嘿,你要的这个需求用Newtonsoft.Json的自定义ContractResolver就能完美搞定,它能全局拦截所有List类型的属性,自动只保留首尾元素,不用在每个类上重复配置,非常适合你说的「任意类型对象」的场景。

实现思路

我们继承DefaultContractResolver,重写CreateProperty方法,针对所有实现了IList接口的属性(包括泛型List<T>),替换它的ValueProvider——在获取属性值时,把原List转换成只包含第一个和最后一个元素的新List(如果元素数量不足2个,就保留原集合,避免空指针或异常)。

完整代码实现

首先创建自定义的ContractResolver:

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class TrimListContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(System.Reflection.MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        
        // 检查属性类型是否是IList(兼容所有List<T>和实现IList的集合)
        if (typeof(IList).IsAssignableFrom(property.PropertyType))
        {
            // 替换ValueProvider,自定义List的读取逻辑
            property.ValueProvider = new TrimListValueProvider(property.ValueProvider);
        }
        
        return property;
    }

    // 自定义ValueProvider,处理List的裁剪逻辑
    private class TrimListValueProvider : IValueProvider
    {
        private readonly IValueProvider _originalProvider;

        public TrimListValueProvider(IValueProvider originalProvider)
        {
            _originalProvider = originalProvider;
        }

        public object GetValue(object target)
        {
            var originalList = _originalProvider.GetValue(target) as IList;
            if (originalList == null || originalList.Count <= 2)
            {
                // 空列表、只有1个元素时直接返回原集合
                return originalList;
            }
            
            // 创建同类型的新集合,只保留首尾元素
            var trimmedList = (IList)System.Activator.CreateInstance(originalList.GetType());
            trimmedList.Add(originalList[0]);
            trimmedList.Add(originalList[originalList.Count - 1]);
            
            return trimmedList;
        }

        public void SetValue(object target, object value)
        {
            // 反序列化时沿用原逻辑,这里我们只关注序列化流程
            _originalProvider.SetValue(target, value);
        }
    }
}

然后修改你的DoTheThing方法,启用这个自定义ContractResolver:

public static string DoTheThing(object dynamicObject)
{
    var settings = new JsonSerializerSettings
    {
        ContractResolver = new TrimListContractResolver(),
        // 可选:格式化输出方便调试,生产环境可移除
        Formatting = Formatting.Indented
    };
    return JsonConvert.SerializeObject(dynamicObject, settings);
}

测试验证

运行你的Main方法:

public static void Main()
{
    var list = new List<Product>(){
        new Product("product1",100),
        new Product("product2",100),
        new Product("product3",100),
        new Product("product4",100)
    };
    var result = new ProductResult(list,0);
    string jsonObj = DoTheThing(result);
    Console.WriteLine(jsonObj);
}

输出结果(格式化后):

{
  "Code": 0,
  "Products": [
    {
      "Name": "product1",
      "Price": 100
    },
    {
      "Name": "product4",
      "Price": 100
    }
  ]
}

完全符合你的需求!而且这个方案支持任意包含List属性的对象,不管是ProductResult还是其他类,只要属性是List/IList类型,都会自动裁剪。

边界情况处理

  • 如果List是空的:序列化后还是空数组
  • 如果List只有1个元素:序列化后只保留这一个元素
  • 如果List正好2个元素:原样保留

备选方案:自定义JsonConverter

如果你只想针对特定的List属性(而非全局所有List)处理,可以用自定义JsonConverter,比如给ProductResult的Products属性加[JsonConverter(typeof(TrimListConverter<Product>))]特性,然后实现转换器:

public class TrimListConverter<T> : JsonConverter<List<T>>
{
    public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer)
    {
        var trimmed = value.Count <= 2 ? value : new List<T> { value[0], value[^1] };
        serializer.Serialize(writer, trimmed);
    }

    public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize<List<T>>(reader);
    }
}

但这种方式需要逐个属性配置,不如ContractResolver灵活,适合局部场景。

内容的提问来源于stack exchange,提问作者B.L.Coskey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 21:12:29