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

基于Newtonsoft,将含多结构嵌套JSON字符串的数组反序列化为类的最佳方法

解决方案:处理嵌套字符串JSON的反序列化问题

首先得明确为什么直接把memo定义为类类型数组会失败:你的JSON里memo的每个元素是被引号包裹的字符串形式的JSON,而非直接的JSON对象。Newtonsoft.Json没法自动把字符串直接转成类实例——类型不匹配,所以直接反序列化肯定会报错。

至于是否必须用两步式处理?答案是不需要手动分步处理,我们可以通过更优雅的方式让反序列化一步完成,当然分步处理也是可行的,下面给你几种不同场景下的最佳实践:


1. 自定义JsonConverter:一步完成自动解析

这是最推荐的方案,通过自定义转换器,让Newtonsoft.Json在反序列化主对象时,自动把memo里的每个字符串解析为对应的类实例。

步骤1:定义实体类

先根据JSON结构定义好对应的强类型类:

public class RootObject
{
    public string x { get; set; }
    public string y { get; set; }
    // 给memo属性添加自定义转换器标记
    [JsonConverter(typeof(MemoItemConverter))]
    public Braums[] memo { get; set; }
    public string z { get; set; }
}

public class Braums
{
    // 包含两种可能的子结构,适配不同的memo元素
    public PrintingData printing_data { get; set; }
    public CancellationReasons cancellation_reasons { get; set; }
}

public class PrintingData
{
    public string customerFirstName { get; set; }
    public int orderNumber { get; set; }
    public string customerLastName { get; set; }
}

public class CancellationReasons
{
    public string who { get; set; }
    public string when { get; set; }
    public string why { get; set; }
}

步骤2:实现自定义JsonConverter

这个转换器负责把字符串形式的JSON解析为Braums实例:

public class MemoItemConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // 指定该转换器处理Braums类型
        return objectType == typeof(Braums);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 读取JSON中的字符串值
        var memoString = (string)reader.Value;
        // 把字符串反序列化为Braums对象(允许单引号适配你的示例格式)
        return JsonConvert.DeserializeObject<Braums>(memoString, new JsonSerializerSettings { AllowSingleQuotes = true });
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 如果需要把对象序列化回字符串形式的JSON,实现反向逻辑
        var braums = (Braums)value;
        var jsonString = JsonConvert.SerializeObject(braums);
        writer.WriteValue(jsonString);
    }
}

步骤3:使用转换器反序列化

现在只需要一次反序列化操作就能得到完整的强类型对象:

var json = @"{""x"": ""testx"", ""y"": ""testy"", ""memo"": [ ""{'braums': {'printing_data': {'customerFirstName': 'xxxxxx', 'orderNumber': 4495, 'customerLastName': 'xxxxxx'}}}"", ""{'braums': {'cancellation_reasons': {'who': 'xxxxxxx', 'when': '11/18/2020 8:02 PM', 'why': 'called to cancel'}}}"", ""z"": ""testz"" }";

var root = JsonConvert.DeserializeObject<RootObject>(json, new JsonSerializerSettings { AllowSingleQuotes = true });

2. 反序列化后处理:简单直观的分步方案

如果不想写自定义转换器,也可以先把memo反序列化为字符串数组,之后再手动解析每个元素:

定义带后处理属性的类

public class RootObject
{
    public string x { get; set; }
    public string y { get; set; }
    // 先存储原始字符串数组
    public string[] memo { get; set; }
    // 用[JsonIgnore]标记,避免序列化/反序列化时被处理
    [JsonIgnore]
    public Braums[] ParsedMemo { get; set; }
}

执行后处理

var root = JsonConvert.DeserializeObject<RootObject>(json, new JsonSerializerSettings { AllowSingleQuotes = true });
// 遍历原始字符串数组,逐个解析为Braums对象
root.ParsedMemo = root.memo.Select(s => JsonConvert.DeserializeObject<Braums>(s, new JsonSerializerSettings { AllowSingleQuotes = true })).ToArray();

3. 封装解析函数:灵活处理不同结构

如果memo里的Braums结构差异很大,你可以封装一个通用函数,根据字符串内容判断解析为对应的子类:

定义子类和解析函数

// 定义不同结构的Braums子类
public class PrintingBraums
{
    public PrintingData printing_data { get; set; }
}

public class CancellationBraums
{
    public CancellationReasons cancellation_reasons { get; set; }
}

// 封装解析函数
public static object ParseMemoItem(string memoString)
{
    var settings = new JsonSerializerSettings { AllowSingleQuotes = true };
    // 先解析为JObject,判断结构类型
    var jObj = JsonConvert.DeserializeObject<JObject>(memoString, settings);
    var braumsObj = jObj["braums"] as JObject;

    if (braumsObj?.ContainsKey("printing_data") == true)
    {
        return braumsObj.ToObject<PrintingBraums>(JsonSerializer.Create(settings));
    }
    else if (braumsObj?.ContainsKey("cancellation_reasons") == true)
    {
        return braumsObj.ToObject<CancellationBraums>(JsonSerializer.Create(settings));
    }

    return null;
}

使用函数解析

var root = JsonConvert.DeserializeObject<RootObject>(json, new JsonSerializerSettings { AllowSingleQuotes = true });
var parsedItems = root.memo.Select(ParseMemoItem).ToArray();

总结

  • 如果需要强类型且结构相对固定,自定义JsonConverter是最佳方案,代码更整洁,无需手动分步处理。
  • 如果结构不固定或者想快速实现,后处理或封装函数也是可行的选择。
  • 你最初的两步式处理是可行的,但可以通过上述方式优化得更优雅。

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 13:27:36