System.Text.Json无法反序列化JSON至泛型类的问题排查
问题:Changed反序列化失败的解决办法
代码定义
抽象类、泛型类及枚举
public abstract class Changed { public abstract object OldValue { get; set; } public abstract object NewValue { get; set; } public TrackedPropertyType Type { get; set; } } public class Changed<T> : Changed { public override object OldValue { get; set; } public override object NewValue { get; set; } public Changed(T oldValue, T newValue, TrackedPropertyType type) { OldValue = oldValue; NewValue = newValue; Type = type; } } public enum TrackedPropertyType { PhoneNumber, Name, Email, BirthDate, WorkedInDodo, SocialNetworkMessagingEnable, IsKeyWord, IsBanned, IsFraud, IsRemove, }
序列化后的JSON示例
{"type": 6, "newValue": 1, "oldValue": 2}
或
{"type": 5, "newValue": true, "oldValue": true}
反序列化代码及异常
反序列化代码:
JsonSerializer.Deserialize<Changed<string>>(json, options);
抛出异常:
System.InvalidOperationException: 反序列化类型'Dodo.Control.Ratings.Model.MysteryShoppers.Events.Changed`1[System.Boolean]'的构造器时,每个参数必须绑定到对象的属性或字段。每个参数名称必须与对象的属性或字段匹配。仅当启用'JsonSerializerOptions.IncludeFields'时才会考虑字段。匹配不区分大小写。
当前JsonSerializerOptions配置
- PropertyNameCaseInsensitive: true
- JsonCamelCaseNamingPolicy: JsonCamelCaseNamingPolicy
解决方案
方法1:添加无参数构造函数
System.Text.Json默认优先使用有参构造函数,但当构造参数无法与JSON属性正确绑定时会报错。给Changed<T>添加无参构造后,序列化器会直接通过属性赋值完成反序列化:
public class Changed<T> : Changed { public override object OldValue { get; set; } public override object NewValue { get; set; } // 添加无参数构造函数 public Changed() { } public Changed(T oldValue, T newValue, TrackedPropertyType type) { OldValue = oldValue; NewValue = newValue; Type = type; } }
方法2:标记构造函数并明确参数映射
如果不想添加无参构造,可给现有有参构造添加[JsonConstructor]属性,并通过[JsonPropertyName]明确参数与JSON键的映射关系,确保序列化器能正确绑定:
using System.Text.Json.Serialization; public class Changed<T> : Changed { public override object OldValue { get; set; } public override object NewValue { get; set; } [JsonConstructor] public Changed( [JsonPropertyName("oldValue")] T oldValue, [JsonPropertyName("newValue")] T newValue, [JsonPropertyName("type")] TrackedPropertyType type) { OldValue = oldValue; NewValue = newValue; Type = type; } }
方法3:重构为强类型属性(推荐)
原代码中父类用object类型属性,子类重写后通过泛型构造赋值,存在类型转换的潜在问题。重构为子类直接定义强类型属性,既能避免反序列化绑定问题,也让代码更清晰:
public abstract class Changed { public TrackedPropertyType Type { get; set; } } public class Changed<T> : Changed { public T OldValue { get; set; } public T NewValue { get; set; } public Changed() { } public Changed(T oldValue, T newValue, TrackedPropertyType type) { OldValue = oldValue; NewValue = newValue; Type = type; } }
内容的提问来源于stack exchange,提问作者Fallingsappy
相关产品推荐
相关产品推荐

