.NET 7/8下System.Text.Json多态参数反序列化问题求解
问题场景
原本通过JsonDerivedType标记了Fruit、Seed等抽象类的多态类型,能正常序列化反序列化。但把Apple类构造函数的参数从Seed改成AppleSeed(Seed的派生类)后,序列化正常,反序列化却失败,用泛型尝试也没解决,想找不用自定义反序列化器的可靠方法。
可行方案
1. 给构造函数参数加JsonConverter属性
直接在Apple类的构造函数参数上指定JsonPolymorphicConverter<Seed>,同时保证抽象类Seed已经用JsonDerivedType标记了AppleSeed:
[JsonDerivedType(typeof(AppleSeed), typeDiscriminator: "AppleSeed")] public abstract class Seed { } public class AppleSeed : Seed { } [JsonDerivedType(typeof(Apple), typeDiscriminator: "Apple")] public abstract class Fruit { } public class Apple : Fruit { public Apple([JsonConverter(typeof(JsonPolymorphicConverter<Seed>))] AppleSeed seed) { Seed = seed; } public AppleSeed Seed { get; } }
JsonPolymorphicConverter会自动识别JSON里的多态类型鉴别器,把对应的Seed实例转换成AppleSeed,完美匹配构造函数参数类型。
2. 全局配置多态反序列化选项
不想每个参数都加属性的话,直接在JsonSerializerOptions里全局配置Seed的多态规则:
var options = new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { if (typeInfo.Type == typeof(Seed)) { typeInfo.PolymorphismOptions = new JsonPolymorphismOptions { TypeDiscriminatorPropertyName = "$type", IgnoreUnrecognizedTypeDiscriminators = true, DerivedTypes = { new JsonDerivedType(typeof(AppleSeed), "AppleSeed") } }; } } } } }; // 反序列化时用这个配置 var apple = JsonSerializer.Deserialize<Apple>(json, options);
全局配置后,所有涉及Seed类型的反序列化都会自动处理多态转换,包括构造函数里的AppleSeed参数。
3. 备选:用默认构造函数或可空参数
如果前两种方法不适用,也可以给Apple类加默认构造函数,或者把构造函数参数设为可空,然后通过属性赋值完成反序列化:
public class Apple : Fruit { // 加个默认构造函数 public Apple() { } public Apple(AppleSeed seed) { Seed = seed; } public AppleSeed Seed { get; set; } }
这种方法是让序列化器先调用默认构造函数创建实例,再给属性赋值,绕开构造函数参数的类型匹配问题,缺点是需要把属性改成可写的,不够严谨,但胜在简单。
核心原理
System.Text.Json默认反序列化构造函数参数时只会精确匹配类型,不会自动处理多态派生类的转换。通过JsonPolymorphicConverter或者全局配置多态选项,就是明确告诉序列化器:这个参数需要识别多态类型,要根据类型鉴别器把基类实例转换成对应的派生类实例。
内容的提问来源于stack exchange,提问作者BradleyImpl

