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

.NET中如何序列化忽略空集合,反序列化自动设为空集合?

序列化忽略空集合、反序列化补全空集合的实现方案

需求背景

存在一批支持JSON序列化/反序列化的POCO,其中大量属性为集合类型。需要实现两个核心逻辑:

  1. 序列化时:仅保留非空集合对应的属性(节省空间、简化人工查看的内容);
  2. 反序列化时:若JSON中缺失集合类型属性,自动将其设为空集合而非null。

现有JsonIgnoreCondition枚举仅支持忽略null或默认值,无法直接处理空集合场景。

示例场景

原POCO定义

public class Data
{
    public DocData MainDoc { get; }
    public IList<DocData> SubDocs { get; }

    public Data(DocData mainDoc, IList<DocData> subDocs)
    {
        MainDoc = mainDoc;
        SubDocs = subDocs;
    }
}

public class DocData
{
    public string Id { get; set; } = string.Empty;
}

当前问题

使用DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull配置序列化时,若SubDocs为空集合,生成的JSON仍会包含该属性:

{
    "MainDoc": { "Id": "Main1" },
    "SubDocs": []
}

期望结果为仅保留非空属性:

{
    "MainDoc": { "Id": "Main1" }
}

此前尝试的自定义转换器会将空集合转为null,但最终JSON仍会输出"SubDocs": null,无法达到忽略属性的目的。


解决方案

通过自定义契约解析器控制序列化逻辑 + 构造函数处理反序列化补全,完全满足需求。

1. 修改POCO构造函数(处理反序列化补全)

添加带[JsonConstructor]标记的构造函数,当JSON缺失集合属性时,将null参数转为空集合:

public class Data
{
    public DocData MainDoc { get; }
    public IList<DocData> SubDocs { get; }

    // 供反序列化使用:自动将null集合转为空集合
    [JsonConstructor]
    public Data(DocData mainDoc, IList<DocData>? subDocs)
    {
        MainDoc = mainDoc;
        SubDocs = subDocs ?? List<DocData>.Empty;
    }

    // 正常业务构造函数
    public Data(DocData mainDoc, IList<DocData> subDocs)
    {
        MainDoc = mainDoc;
        SubDocs = subDocs;
    }
}

2. 自定义契约解析器(控制序列化忽略空集合)

继承DefaultJsonTypeInfoResolver,重写GetTypeInfo方法,为集合类型属性设置序列化条件:

using System.Collections;
using System.Text.Json;
using System.Text.Json.Serialization;

public class IgnoreEmptyCollectionsResolver : DefaultJsonTypeInfoResolver
{
    public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
    {
        JsonTypeInfo typeInfo = base.GetTypeInfo(type, options);
        
        foreach (JsonPropertyInfo property in typeInfo.Properties)
        {
            // 判断是否为集合类型(排除字符串,因为string实现了IEnumerable<char>)
            if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && 
                property.PropertyType != typeof(string))
            {
                // 设置序列化条件:仅当集合非空时才序列化该属性
                property.ShouldSerialize = (obj, value) =>
                {
                    if (value is IEnumerable enumerable)
                    {
                        return enumerable.GetEnumerator().MoveNext();
                    }
                    return value != null;
                };
            }
        }
        
        return typeInfo;
    }
}

3. 使用示例

配置序列化选项并验证效果:

// 初始化序列化选项
var jsonOptions = new JsonSerializerOptions
{
    TypeInfoResolver = new IgnoreEmptyCollectionsResolver(),
    WriteIndented = true // 格式化输出,便于查看
};

// 测试序列化:SubDocs为空集合
var emptySubDocsData = new Data(new DocData { Id = "Main1" }, List<DocData>.Empty);
string serializedJson = JsonSerializer.Serialize(emptySubDocsData, jsonOptions);
// 输出结果:仅包含MainDoc属性,无SubDocs
Console.WriteLine(serializedJson);

// 测试反序列化:JSON中无SubDocs属性
string jsonWithoutSubDocs = @"{""MainDoc"": {""Id"": ""Main2""}}";
var deserializedData = JsonSerializer.Deserialize<Data>(jsonWithoutSubDocs, jsonOptions);
// 验证:SubDocs为空集合而非null
Console.WriteLine(deserializedData?.SubDocs.Count); // 输出0

方案说明

  • 序列化逻辑:通过契约解析器的ShouldSerialize回调,直接跳过空集合属性的序列化,从根源上避免空集合出现在JSON中,比自定义转换器更直接。
  • 反序列化逻辑:利用[JsonConstructor]标记的构造函数,在反序列化过程中自动将缺失属性对应的null参数转为空集合,确保POCO的集合属性始终非null。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:45:08