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

基于Newtonsoft.Json实现JSON字符串的条件反序列化优化

解决方案:流式读取JSON,仅反序列化符合条件的项

刚好之前处理过类似的场景——当缓存里存了几千条记录的JSON数组时,全量反序列化再做Linq查询确实会造成不必要的性能浪费。好在Newtonsoft.Json(Json.NET)提供了底层流式读取API,能让我们逐个扫描JSON节点,只处理符合筛选条件的对象,完全不用把整个数组加载到内存中。

方法1:根据单个条件获取匹配的单个对象

比如你要找Code为"DUPLICATE_CHECK"的记录,可以用下面的方法:

public static SomeClass GetSingleItemByCode(string jsonCache, string targetCode)
{
    if (string.IsNullOrEmpty(jsonCache))
        return null;

    // 用StringReader和JsonTextReader流式读取JSON
    using (var stringReader = new StringReader(jsonCache))
    using (var jsonReader = new JsonTextReader(stringReader))
    {
        // 跳过数组开头的[符号(如果当前没指向StartArray的话)
        if (jsonReader.TokenType != JsonToken.StartArray)
            jsonReader.Read();

        // 遍历数组中的每个元素
        while (jsonReader.Read())
        {
            // 遇到对象开始的节点时处理
            if (jsonReader.TokenType == JsonToken.StartObject)
            {
                // 加载当前对象为JObject(仅加载这一个对象,不是整个数组)
                var jObject = JObject.Load(jsonReader);
                var codeValue = jObject["Code"]?.ToString();
                
                // 匹配到目标Code时,反序列化为SomeClass并返回
                if (codeValue == targetCode)
                {
                    return jObject.ToObject<SomeClass>();
                }
            }
        }
    }

    // 没找到匹配项返回null
    return null;
}

方法2:根据条件获取多个匹配对象

如果需要获取多个符合条件的记录(比如所有Type为"0"的项),可以稍作修改:

public static List<SomeClass> GetItemsByType(string jsonCache, string targetType)
{
    var results = new List<SomeClass>();
    if (string.IsNullOrEmpty(jsonCache))
        return results;

    using (var stringReader = new StringReader(jsonCache))
    using (var jsonReader = new JsonTextReader(stringReader))
    {
        if (jsonReader.TokenType != JsonToken.StartArray)
            jsonReader.Read();

        while (jsonReader.Read())
        {
            if (jsonReader.TokenType == JsonToken.StartObject)
            {
                var jObject = JObject.Load(jsonReader);
                var typeValue = jObject["Type"]?.ToString();
                
                if (typeValue == targetType)
                {
                    results.Add(jObject.ToObject<SomeClass>());
                }
            }
        }
    }

    return results;
}

方法3:通用筛选方法(支持自定义条件)

如果需要更灵活的筛选逻辑,可以把筛选条件做成委托,适配各种查询需求:

public static List<SomeClass> FilterJsonItems(string jsonCache, Func<JObject, bool> filter)
{
    var results = new List<SomeClass>();
    if (string.IsNullOrEmpty(jsonCache) || filter == null)
        return results;

    using (var stringReader = new StringReader(jsonCache))
    using (var jsonReader = new JsonTextReader(stringReader))
    {
        if (jsonReader.TokenType != JsonToken.StartArray)
            jsonReader.Read();

        while (jsonReader.Read())
        {
            if (jsonReader.TokenType == JsonToken.StartObject)
            {
                var jObject = JObject.Load(jsonReader);
                // 用自定义筛选条件判断是否保留当前对象
                if (filter(jObject))
                {
                    results.Add(jObject.ToObject<SomeClass>());
                }
            }
        }
    }

    return results;
}

调用示例:

// 找Code为DUPLICATE_CHECK的第一个项
var duplicateItem = FilterJsonItems(cacheJson, j => j["Code"]?.ToString() == "DUPLICATE_CHECK").FirstOrDefault();

// 找所有Type为0且IsActive为Y的项
var activeType0Items = FilterJsonItems(cacheJson, j => 
    j["Type"]?.ToString() == "0" && j["IsActive"]?.ToString() == "Y");

核心优势

  • 极低内存占用:每次仅处理单个JSON对象,不会把整个几千条记录的数组加载到内存中
  • 更快的查询速度:找到匹配项后可以立即返回(比如方法1),不需要遍历完整个数组
  • 兼容性强:JObject.ToObject<SomeClass>()和你原来用的JsonConvert.DeserializeObject<T>效果完全一致,支持复杂嵌套属性

注意事项

  • 确保缓存中的JSON是合法的数组格式,如果格式可能异常,可以在方法中添加try-catch块处理
  • JObject.Load(jsonReader)会自动消耗当前的StartObject节点,不需要额外调用jsonReader.Read(),否则会跳过下一个节点

内容的提问来源于stack exchange,提问作者Neeraj Kumar Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:20:22