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

如何让Json.NET序列化字典时保留键但跳过默认值内容?

解决Json.NET序列化字典时跳过默认值但保留键的问题

我最近碰到这么个需求:用Json.NET序列化字典的时候,希望跳过那些和默认值一致的字段值,但得保留对应的键,这样后续反序列化的时候还能完整恢复结构。举个具体的场景:

我有这么一段代码:

public Dictionary<int, Item> allItems;
public class Item { public bool IsSelected; public List<string> SelectionInfo; }

现在用工具序列化后得到的JSON是这样的:

"allItems": { "0": { "IsSelected": true, "SelectionInfo": [ "yes", "maybe", "no" ] }, "1": { "IsSelected": false, "SelectionInfo": [] } }

但我想要的输出是这样的——把默认值的字段去掉,但保留键:

"allItems": { "0": { "IsSelected": true, "SelectionInfo": [ "yes", "maybe", "no" ] }, "1": { } }

而且序列化工具在另一个项目里,调用方式是Utility.Please.TurnToJson(item);,我还得保证跨项目的JSON序列化一致性。如果必须用自定义转换器,得知道怎么把它传给这个工具,比如类似Utility.Please.TurnToJson(item, new List<object>(){ typeof(Custom1), typeof(Custom2) });这种调用方式。

核心解决方案:自定义JsonConverter

要实现这个需求,核心就是写一个针对Item类的自定义JsonConverter,在序列化时判断属性是否为默认值,只保留非默认值的字段;反序列化时补全默认值,确保结构完整。

1. 编写自定义转换器

先写一个ItemConverter,继承JsonConverter<Item>:

public class ItemConverter : JsonConverter<Item>
{
    public override void WriteJson(JsonWriter writer, Item value, JsonSerializer serializer)
    {
        var obj = new JObject();
        
        // 判断IsSelected是否不是默认值(bool默认是false)
        if (value.IsSelected != default(bool))
        {
            obj.Add(nameof(Item.IsSelected), value.IsSelected);
        }
        
        // 判断SelectionInfo是否有内容(这里默认是空列表,所以判断Count>0)
        if (value.SelectionInfo?.Count > 0)
        {
            obj.Add(nameof(Item.SelectionInfo), JArray.FromObject(value.SelectionInfo, serializer));
        }
        
        obj.WriteTo(writer);
    }

    public override Item ReadJson(JsonReader reader, Type objectType, Item existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 反序列化时补全默认值,保证结构完整
        var obj = JObject.Load(reader);
        var item = new Item();
        
        item.IsSelected = obj.TryGetValue(nameof(Item.IsSelected), out var isSelectedToken) 
            ? isSelectedToken.ToObject<bool>(serializer) 
            : default(bool);
            
        item.SelectionInfo = obj.TryGetValue(nameof(Item.SelectionInfo), out var selectionInfoToken) 
            ? selectionInfoToken.ToObject<List<string>>(serializer) 
            : new List<string>();
            
        return item;
    }
}

2. 传入自定义转换器到工具

根据你提到的工具调用方式,它接受一个包含转换器类型的List<object>参数,那调用的时候直接传ItemConverter的类型即可:

var customConverters = new List<object> { typeof(ItemConverter) };
string serializedJson = Utility.Please.TurnToJson(yourObjectInstance, customConverters);

这里要注意:工具内部需要把传入的类型实例化成JsonConverter对象,然后添加到JsonSerializerSettings的Converters集合里,所以你的ItemConverter必须有无参构造函数(上面的例子已经满足)。

3. 替代方案:用特性标记类

如果工具暂时不支持传入转换器参数,你可以直接在Item类上标记JsonConverter特性,这样Json.NET会自动使用这个转换器,跨项目只要引用了这个类和转换器,就能保证序列化一致:

[JsonConverter(typeof(ItemConverter))]
public class Item { public bool IsSelected; public List<string> SelectionInfo; }

注意事项

  • 默认值的判断要根据实际业务来调整:比如SelectionInfo如果默认是null,那判断逻辑就要改成value.SelectionInfo != null,而不是Count>0。
  • 反序列化一定要补全默认值:这样后续恢复对象时,不会出现属性为null或者不符合预期默认值的情况,保证结构完整性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:15:54