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
相关产品推荐
相关产品推荐

