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

System.Text.Json序列化dynamic对象时无法忽略null值的问题

序列化Dynamic对象时忽略Null属性的解决方案

我需要将dynamic对象(实际场景是SQL查询结果存入dynamic对象,包含大量null列)序列化为JSON时,抑制所有null属性。但使用System.Text.Json.JsonSerializer.Serialize()时,不管设置哪种JsonIgnoreCondition选项都无效——这个选项对强类型有效,但对dynamic对象(比如ExpandoObject)不起作用。

复现代码

using System.Dynamic;
using System.Text.Json.Serialization;
using System.Text.Json;

var foo = new Foo();
var fooJson = JsonSerializer.Serialize(foo, new JsonSerializerOptions() { WriteIndented = true});
var fooJson1 = JsonSerializer.Serialize(foo, new JsonSerializerOptions() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault});
var fooJson2 = JsonSerializer.Serialize(foo, new JsonSerializerOptions() {WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull});

Console.WriteLine("fooJson:");
Console.WriteLine(fooJson);
Console.WriteLine("fooJson1:");
Console.WriteLine(fooJson1);
Console.WriteLine("fooJson2:");
Console.WriteLine(fooJson2);

dynamic dynamicFoo = new ExpandoObject();
dynamicFoo.Prop1 = "something";
dynamicFoo.Prop2 = (int?)null;
dynamicFoo.Prop3 = (string)null;

var dynamicFooJson = JsonSerializer.Serialize(dynamicFoo, new JsonSerializerOptions() { WriteIndented = true});
var dynamicFooJson1 = JsonSerializer.Serialize(dynamicFoo, new JsonSerializerOptions() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault});
var dynamicFooJson2 = JsonSerializer.Serialize(dynamicFoo, new JsonSerializerOptions() {WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull});

Console.WriteLine("dynamicFooJson:");
Console.WriteLine(dynamicFooJson);
Console.WriteLine("dynamicFooJson1:");
Console.WriteLine(dynamicFooJson1);
Console.WriteLine("dynamicFooJson2:");
Console.WriteLine(dynamicFooJson2);


public class Foo
{
    public string Prop1 {get;set;}
    public int Prop2 {get;set;}
    public int? Prop3 {get;set;}
}

执行输出

fooJson:
{
  "Prop1": null,
  "Prop2": 0,
  "Prop3": null
}
fooJson1:
{}
fooJson2:
{
  "Prop2": 0
}
dynamicFooJson:
{
  "Prop1": "something",
  "Prop2": null,
  "Prop3": null
}
dynamicFooJson1:
{
  "Prop1": "something",
  "Prop2": null,
  "Prop3": null
}
dynamicFooJson2:
{
  "Prop1": "something",
  "Prop2": null,
  "Prop3": null
}

解决方案

方法1:手动过滤Null值

ExpandoObject实现了IDictionary<string, object>接口,可先转为字典过滤掉值为null的项,再序列化:

dynamic dynamicFoo = new ExpandoObject();
dynamicFoo.Prop1 = "something";
dynamicFoo.Prop2 = (int?)null;
dynamicFoo.Prop3 = (string)null;

// 过滤null值
var filteredDict = ((IDictionary<string, object>)dynamicFoo)
    .Where(kv => kv.Value != null)
    .ToDictionary(kv => kv.Key, kv => kv.Value);

var json = JsonSerializer.Serialize(filteredDict, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);

输出:

{
  "Prop1": "something"
}

方法2:自定义全局JsonConverter

如果需要统一处理所有ExpandoObject的序列化,可自定义转换器跳过null值:

public class ExpandoObjectNullIgnoringConverter : JsonConverter<ExpandoObject>
{
    public override ExpandoObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options);
        var expando = new ExpandoObject() as IDictionary<string, object>;
        if (dict != null)
        {
            foreach (var kv in dict)
            {
                expando.Add(kv);
            }
        }
        return (ExpandoObject)expando;
    }

    public override void Write(Utf8JsonWriter writer, ExpandoObject value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        foreach (var kv in value as IDictionary<string, object>)
        {
            if (kv.Value != null)
            {
                writer.WritePropertyName(kv.Key);
                JsonSerializer.Serialize(writer, kv.Value, options);
            }
        }
        writer.WriteEndObject();
    }
}

使用方式:

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters = { new ExpandoObjectNullIgnoringConverter() }
};

var json = JsonSerializer.Serialize(dynamicFoo, options);
Console.WriteLine(json);

内容的提问来源于stack exchange,提问作者Mr. T

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:23:08