使用System.Text.Json序列化时如何限制缩进深度?
如何在System.Text.Json序列化时限制缩进深度
我复用了一个原本针对Newtonsoft.Json的问题,现在想应用到System.Text.Json上:使用System.Text.Json序列化对象时,能否在达到指定深度后停止缩进?
比如针对下面的对象(清单1),能否通过继承JsonConverter或JsonWriter类,只缩进至特定层级,得到输出2或输出3的结果,而非全缩进的输出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:完全缩进
[ { "Name": "John", "Age": 5, "Address": { "Home": "No. 123, Oak Street", "Email": "john@mail.com" }, "Extra": { "Serials": [ 20, 30, 40, 50 ] } }, { "Name": "Jean", "Age": 2, "Address": { "Home": "No. 321, Cliff Road", "Email": "jean@mail.com" }, "Extra": { "Serials": [ 25, 35, 45, 55 ] } } ]
输出2:缩进至两层深度
[ { "Name": "John", "Age": 5, "Address": { "Home": "No. 123, Oak Street", "Email": "john@mail.com" }, "Extra": { "Serials": [ 20, 30, 40, 50 ] } }, { "Name": "Jean", "Age": 2, "Address": { "Home": "No. 321, Cliff Road", "Email": "jean@mail.com" }, "Extra": { "Serials": [ 25, 35, 45, 55 ] } } ]
输出3:缩进至三层深度
[ { "Name": "John", "Age": 5, "Address": { "Home": "No. 123, Oak Street", "Email": "john@mail.com" }, "Extra": { "Serials": [ 20, 30, 40, 50 ] } }, { "Name": "Jean", "Age": 2, "Address": { "Home": "No. 321, Cliff Road", "Email": "jean@mail.com" }, "Extra": { "Serials": [ 25, 35, 45, 55 ] } } ]
解决方案:自定义LimitedIndentJsonWriter
System.Text.Json没有内置的缩进深度限制功能,我们可以通过继承Utf8JsonWriter来实现需求,核心思路是跟踪当前序列化深度,超过设定值时自动切换为紧凑格式。
1. 实现自定义JsonWriter
public class LimitedIndentJsonWriter : Utf8JsonWriter { private readonly int _maxIndentDepth; private int _currentDepth = 0; private readonly JsonWriterOptions _originalOptions; public LimitedIndentJsonWriter(Stream stream, JsonWriterOptions options, int maxIndentDepth) : base(stream, options) { _maxIndentDepth = maxIndentDepth; _originalOptions = options; } public override void WriteStartObject() { _currentDepth++; UpdateIndentSetting(); base.WriteStartObject(); } public override void WriteEndObject() { base.WriteEndObject(); _currentDepth--; UpdateIndentSetting(); } public override void WriteStartArray() { _currentDepth++; UpdateIndentSetting(); base.WriteStartArray(); } public override void WriteEndArray() { base.WriteEndArray(); _currentDepth--; UpdateIndentSetting(); } private void UpdateIndentSetting() { // 当前深度未超过限制时保留缩进,超过则切换为紧凑格式 var shouldIndent = _currentDepth <= _maxIndentDepth && _originalOptions.Indented; Options = _originalOptions with { Indented = shouldIndent }; } }
2. 封装序列化工具方法
public static class JsonSerializerHelper { public static string SerializeWithLimitedIndent<T>(T value, int maxIndentDepth, JsonSerializerOptions? options = null) { options ??= new JsonSerializerOptions(); var originalIndented = options.Indented; options.Indented = true; // 确保基础缩进开启,后续由自定义Writer控制 using var stream = new MemoryStream(); using var writer = new LimitedIndentJsonWriter( stream, new JsonWriterOptions { Indented = options.Indented, Encoder = options.Encoder, SkipValidation = options.SkipValidation, MaxDepth = options.MaxDepth }, maxIndentDepth ); JsonSerializer.Serialize(writer, value, options); writer.Flush(); stream.Position = 0; return Encoding.UTF8.GetString(stream.ToArray()); } }
3. 使用示例
// 生成两层深度缩进的结果(对应输出2) var result2 = JsonSerializerHelper.SerializeWithLimitedIndent(items, 2); Console.WriteLine(result2); // 生成三层深度缩进的结果(对应输出3) var result3 = JsonSerializerHelper.SerializeWithLimitedIndent(items, 3); Console.WriteLine(result3);
关键说明
- 自定义Writer通过
_currentDepth跟踪序列化层级,进入对象/数组时深度+1,退出时-1 - 超过
_maxIndentDepth后自动关闭缩进,该层级及以下的内容会被压缩到一行 - 保留了原始
JsonSerializerOptions的所有配置,仅动态修改缩进状态
内容的提问来源于Stack Exchange,提问作者Frank Schwieterman
相关产品推荐
相关产品推荐

