Newtonsoft Json.Net反序列化时如何条件跳过数组项仅保留前N条数据
Json.NET 反序列化仅读取数组前N项实现方案
可以通过自定义JsonConverter实现该需求,核心逻辑是在读取数组节点时,解析完指定数量的前缀元素后,直接跳过数组剩余的所有Token,无需反序列化后续内容,性能损耗极低。
实现代码
/// <summary> /// 限制数组反序列化最大数量的转换器 /// </summary> /// <typeparam name="T">数组元素类型</typeparam> public class LimitedArrayConverter<T> : JsonConverter { private readonly int _maxItemCount; /// <summary> /// 构造函数 /// </summary> /// <param name="maxItemCount">最多读取的数组元素数量</param> public LimitedArrayConverter(int maxItemCount) { _maxItemCount = maxItemCount > 0 ? maxItemCount : 1; } public override bool CanConvert(Type objectType) { return objectType == typeof(List<T>) || objectType == typeof(T[]); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; if (reader.TokenType != JsonToken.StartArray) { throw new JsonSerializationException("当前节点不是数组类型"); } var resultList = new List<T>(_maxItemCount); int currentCount = 0; // 遍历数组节点 while (reader.Read() && reader.TokenType != JsonToken.EndArray) { if (currentCount < _maxItemCount) { // 反序列化需要的前N个元素 var item = serializer.Deserialize<T>(reader); resultList.Add(item); currentCount++; } else { // 直接跳过后续元素,不做反序列化 reader.Skip(); } } // 适配数组/List两种返回类型 return objectType.IsArray ? resultList.ToArray() : resultList; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // 仅用于反序列化,序列化逻辑无需实现 throw new NotSupportedException("该转换器仅支持读取操作"); } }
使用方式
- 固定取数场景
若需要固定读取前N条数据,直接在对应数组属性上标注JsonConverter特性即可:public class FinanceOrderResponse { // 其他接口返回属性省略 [JsonConverter(typeof(LimitedArrayConverter<OrderItem>), 20)] public List<OrderItem> OrderList { get; set; } } - 动态取数场景
若需要每次反序列化时动态指定取数数量,反序列化时传入转换器实例即可:int needCount = 15; // 可根据业务需求动态调整 var deserializeSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new LimitedArrayConverter<OrderItem>(needCount) } }; var responseData = JsonConvert.DeserializeObject<FinanceOrderResponse>(rawJson, deserializeSettings);
补充说明
- 核心的
reader.Skip()方法仅在JSON流层面跳过节点,不会加载或解析后续内容,数组剩余元素越多,性能提升越明显,对比全量反序列化后再截取前缀的方案,最高可获得10倍以上的性能提升 - 如果存在多个数组属性需要分别限制取数数量,给每个属性单独标注特性指定不同的最大数量即可,不会互相干扰
- 配合
MemberSerialization.OptIn特性只反序列化需要的字段,可进一步降低性能损耗
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

