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

C#:如何在JsonConvert序列化输出中覆盖可空属性的null值

解决可空属性未初始化时自定义序列化值的问题

问题核心是:Newtonsoft.Json(默认序列化逻辑)对未初始化的可空属性会直接输出null,且不会触发针对值类型的自定义JsonConverter。要实现将未赋值的可空属性替换为指定值(比如123),可以通过以下两种方案解决:

方案一:修改自定义Converter以支持可空类型

让自定义Converter同时处理值类型和对应的可空类型,在WriteJson中直接处理null情况:

public class MyConverter : JsonConverter
{
    // 同时匹配int和int?类型
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(int) || objectType == typeof(int?);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 若值为null(对应未初始化的int?),输出123,否则输出实际值
        int outputValue = value as int? ?? 123;
        writer.WriteValue(outputValue);
    }

    // 反序列化逻辑按需实现
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return objectType == typeof(int?) ? null : (object)123;
        }
        return Convert.ToInt32(reader.Value);
    }
}

在模型属性上直接应用该Converter:

public class MyModel
{
    [JsonConverter(typeof(MyConverter))]
    public int MyInt { get; set; }

    [JsonConverter(typeof(MyConverter))]
    public int? OptInt { get; set; }
}

此时无论OptInt是否赋值,都会触发WriteJson方法,未赋值时自动替换为123输出。

方案二:使用ContractResolver针对单个属性处理

如果只需要对特定可空属性做自定义null替换,无需修改全局Converter,可以自定义ContractResolver:

public class CustomContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        // 仅对名为OptInt的int?属性生效
        if (property.PropertyName == "OptInt" && property.PropertyType == typeof(int?))
        {
            property.ValueProvider = new CustomNullReplacerProvider(property.ValueProvider);
        }

        return property;
    }

    // 自定义值提供器,替换null为指定值
    private class CustomNullReplacerProvider : IValueProvider
    {
        private readonly IValueProvider _originalProvider;

        public CustomNullReplacerProvider(IValueProvider originalProvider)
        {
            _originalProvider = originalProvider;
        }

        public void SetValue(object target, object value)
        {
            _originalProvider.SetValue(target, value);
        }

        public object GetValue(object target)
        {
            object value = _originalProvider.GetValue(target);
            // 若值为null,返回123
            return value ?? 123;
        }
    }
}

序列化时指定使用该ContractResolver,同时确保NullValueHandling设为Include(避免属性被省略):

var serializerSettings = new JsonSerializerSettings
{
    ContractResolver = new CustomContractResolver(),
    NullValueHandling = NullValueHandling.Include
};

var model = new MyModel { MyInt = 1 };
string json = JsonConvert.SerializeObject(model, serializerSettings);
// 输出结果:{"MyInt":1,"OptInt":123}

注意事项

  • 若使用的是System.Text.Json,逻辑类似但API不同:需自定义JsonConverter<Nullable<int>>或JsonConverterFactory来处理可空类型的null替换
  • 方案一适合多个属性需要统一处理的场景,方案二更灵活,可针对单个属性定制
  • 务必不要设置NullValueHandling.Ignore,否则未赋值的null属性会被直接省略,无法触发替换逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:33:38