使用自定义JsonConverter反序列化时如何为JSON缺失属性赋值
问题原因
你当前的方案不生效有两个核心原因:
- Newtonsoft.Json 默认仅当JSON字符串中存在对应属性键时,才会调用绑定到该属性的自定义
JsonConverter,缺失属性不会触发属性级转换器执行 - 你编写的
InternalIDConverter中CanConvert方法直接返回false,即使触发转换器逻辑也会直接被跳过
方案1:使用OnDeserialized特性回调(最简方案)
直接在实体类中添加反序列化完成后的自动回调方法,属于反序列化流程内的原生支持能力,无需额外配置:
using System.Runtime.Serialization; public class TestClass { public int InternalID { get; set; } public int IdRemittance { get; set; } public string IDCountry { get; set; } public string OperationAction { get; set; } public bool BusinessToBusiness { get; set; } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { // 此处编写InternalID的赋值逻辑,支持基于当前对象的其他属性计算 // 示例:用IdRemittance赋值,或者自定义自增逻辑均可 InternalID = IdRemittance * 100; } }
原反序列化调用代码无需任何修改即可生效。
方案2:自定义ContractResolver(无需修改实体类)
如果不能修改TestClass的定义,可以通过自定义合约解析器实现全局/指定类的缺失属性赋值:
using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System.Reflection; using System.Threading; public class InternalIDContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); if (property.DeclaringType == typeof(TestClass) && property.PropertyName == nameof(TestClass.InternalID)) { // 强制JSON缺失该属性时也填充默认值 property.DefaultValueHandling = DefaultValueHandling.Populate; property.DefaultValueProvider = new InternalIDValueProvider(); } return property; } } public class InternalIDValueProvider : IValueProvider { // 示例:全局自增ID private int _incrementId = 0; public object GetValue(object target) => ((TestClass)target).InternalID; public void SetValue(object target, object value) => ((TestClass)target).InternalID = Interlocked.Increment(ref _incrementId); }
反序列化时传入配置即可:
private void button11_Click(object sender, EventArgs e) { string json = "[{\"IDCountry\":\"AK\",\"BusinessToBusiness\":false,\"IdRemittance\":2,\"OperationAction\":\"U\"},{\"IDCountry\":\"AK\",\"BusinessToBusiness\":true,\"IdRemittance\":14,\"OperationAction\":\"U\"}]"; var settings = new JsonSerializerSettings { ContractResolver = new InternalIDContractResolver() }; var data = JsonConvert.DeserializeObject<List<TestClass>>(json, settings); }
方案3:类级自定义JsonConverter
如果需要完全控制TestClass的反序列化流程,可以定义类级转换器:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class TestClassConverter : JsonConverter<TestClass> { public override TestClass ReadJson(JsonReader reader, Type objectType, TestClass existingValue, bool hasExistingValue, JsonSerializer serializer) { JObject jObject = JObject.Load(reader); // 先反序列化所有JSON中存在的属性 var instance = jObject.ToObject<TestClass>(); // 给缺失的InternalID赋值 instance.InternalID = 你的自定义赋值逻辑; return instance; } public override void WriteJson(JsonWriter writer, TestClass value, JsonSerializer serializer) { // 序列化逻辑按需实现 serializer.Serialize(writer, value); } }
反序列化时传入转换器即可:
var data = JsonConvert.DeserializeObject<List<TestClass>>(json, new TestClassConverter());
内容的提问来源于stack exchange,提问作者Neeraj Kumar Gupta
相关产品推荐
相关产品推荐

