首页 > 解决方案 > 使用 Newtonsoft.Json 序列化时如何限制缩进深度

问题描述

使用 Newtonsoft.Json 序列化对象时,有没有办法在给定深度后停止序列化值的缩进?

例如,给定清单 1中的对象,有没有办法将JsonConverterJsonWriter缩进到某个级别,以便在Dump 2Dump 3中获得输出而不是Dump 1中的输出?

清单 1

var items = new[] {
    new { Name = "John",
          Age = 5,
          Address = new { Home = "No. 123, Oak Street", Email = "john@mail.com" },
          Extra = new { Serials = new[] { 20, 30, 40, 50 } }
    },
    new { Name = "Jean",
          Age = 2,
          Address = new { Home = "No. 321, Cliff Road", Email = "jean@mail.com" },
          Extra = new { Serials = new[] { 25, 35, 45, 55 } }
    }
};

转储 1:完全缩进

[
  {
    “姓名”:“约翰”,
    “年龄”:5,
    “地址”: {
      “家”:“橡树街123号”,
      “电子邮件”:“john@mail.com”
    },
    “额外的”: {
      “连续剧”:[
        20,
        30,
        40,
        50
      ]
    }
  },
  {
    “姓名”:“让”,
    “年龄”:2,
    “地址”: {
      “家”:“悬崖路321号”,
      “电子邮件”:“jean@mail.com”
    },
    “额外的”: {
      “连续剧”:[
        25,
        35,
        45,
        55
      ]
    }
  }
]

转储 2:深两层

[
  {
    “姓名”:“约翰”,
    “年龄”:5,
    “地址”:{“家”:“橡树街 123 号”,“电子邮件”:“john@mail.com”},
    “额外”:{“连续剧”:[20、30、40、50]}
  },
  {
    “姓名”:“让”,
    “年龄”:2,
    “地址”:{“家”:“悬崖路321号”,“电子邮件”:“jean@mail.com”},
    “额外”:{“连续剧”:[25、35、45、55]}
  }
]

转储 3:三层深

[
  {
    “姓名”:“约翰”,
    “年龄”:5,
    “地址”: {
      “家”:“橡树街123号”,
      “电子邮件”:“john@mail.com”
    },
    “额外的”: {
      “连续剧”:[20、30、40、50]
    }
  },
  {
    “姓名”:“让”,
    “年龄”:2,
    “地址”: {
      “家”:“悬崖路321号”,
      “电子邮件”:“jean@mail.com”
    },
    “额外的”: {
      “连续剧”: [ 25, 35, 45, 55 ]
    }
  }
]

标签: c#json.netjson.net

解决方案


是的,你可以通过继承这样的子类来限制缩进深度JsonTextWriter

public class CustomIndentingJsonTextWriter : JsonTextWriter
{
    public int? MaxIndentDepth { get; set; } 

    public CustomIndentingJsonTextWriter(TextWriter writer) : base(writer)
    {
        Formatting = Formatting.Indented;
    }

    public override void WriteStartArray()
    {
        base.WriteStartArray();
        if (MaxIndentDepth.HasValue && Top > MaxIndentDepth.Value) 
            Formatting = Formatting.None;
    }

    public override void WriteStartObject()
    {
        base.WriteStartObject();
        if (MaxIndentDepth.HasValue && Top > MaxIndentDepth.Value) 
            Formatting = Formatting.None;
    }

    public override void WriteEndArray()
    {
        base.WriteEndArray();
        if (MaxIndentDepth.HasValue && Top <= MaxIndentDepth.Value) 
            Formatting = Formatting.Indented;
    }

    public override void WriteEndObject()
    {
        base.WriteEndObject();
        if (MaxIndentDepth.HasValue && Top <= MaxIndentDepth.Value) 
            Formatting = Formatting.Indented;
    }
}

您可以创建一个辅助方法以方便使用编写器:

public static string SerializeWithCustomIndenting(object obj, int? maxIdentDepth = null)
{
    using (StringWriter sw = new StringWriter())
    using (CustomIndentingJsonTextWriter jw = new CustomIndentingJsonTextWriter(sw))
    {
        jw.MaxIndentDepth = maxIdentDepth;
        JsonSerializer ser = new JsonSerializer();
        ser.Serialize(jw, obj);
        return sw.ToString();
    }
}

然后你可以这样做:

string json = SerializeWithCustomIndenting(yourObject, 2);  // indent to 2 levels max

这是一个工作演示:https ://dotnetfiddle.net/XhwsGF


推荐阅读