C# JSON反序列化如何根据PartType值实例化Component对应子类
多态JSON列表反序列化实现方案
这是典型的多态反序列化场景:默认JSON反序列化器只会按照属性声明的基类Component实例化对象,不会自动识别子类类型,需要自定义类型映射规则,根据每个列表项的PartType字段值创建对应子类实例。
以下分别给出.NET生态最常用的两个JSON序列化库的实现方式:
方案一:Newtonsoft.Json (Json.NET)
这是.NET生态使用最广泛的第三方JSON库,通过自定义类型转换器即可实现需求:
- 编写多态转换器,读取
PartType字段映射对应类型
public class ComponentTypeConverter : JsonConverter<Component> { public override Component ReadJson(JsonReader reader, Type objectType, Component existingValue, bool hasExistingValue, JsonSerializer serializer) { // 加载当前JSON对象,读取类型标识字段 JObject currentObj = JObject.Load(reader); string partType = currentObj["PartType"]?.ToString(); // 根据类型标识创建对应子类实例 Component instance = partType switch { nameof(Window) => new Window(), nameof(Engine) => new Engine(), nameof(Door) => new Door(), _ => new Component() // 未知类型回退到基类 }; // 自动填充所有匹配字段到实例 serializer.Populate(currentObj.CreateReader(), instance); return instance; } public override void WriteJson(JsonWriter writer, Component value, JsonSerializer serializer) { // 无序列化需求可直接抛异常,标记CanWrite为false即可跳过该方法 throw new NotImplementedException(); } public override bool CanWrite => false; }
- 反序列化时加载转换器
var serializerSettings = new JsonSerializerSettings { Converters = { new ComponentTypeConverter() } }; Product product = JsonConvert.DeserializeObject<Product>(apiResponseJson, serializerSettings);
如果不想每次反序列化都传入配置,可以直接在Product类的Components属性上标记[JsonConverter(typeof(ComponentTypeConverter))]特性,转换器会自动生效。
方案二:System.Text.Json (.NET 内置JSON库)
根据你使用的.NET版本不同,实现方式略有区别:
.NET 7 及以上版本
框架原生支持多态反序列化配置,不需要写自定义转换器,直接在基类上标记特性即可:
// 指定类型判别字段为PartType [JsonPolymorphic(TypeDiscriminatorPropertyName = nameof(Component.PartType))] // 映射每个类型标识对应的子类 [JsonDerivedType(typeof(Window), "Window")] [JsonDerivedType(typeof(Engine), "Engine")] [JsonDerivedType(typeof(Door), "Door")] public class Component { public string PartType { get; set; } }
配置完成后直接调用默认反序列化方法即可:
Product product = JsonSerializer.Deserialize<Product>(apiResponseJson);
.NET 6 及以下版本
低版本没有内置多态特性,需要自定义转换器实现,逻辑和Newtonsoft.Json类似:
public class ComponentTypeConverter : JsonConverter<Component> { public override Component Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 解析当前JSON节点,读取类型标识 using JsonDocument doc = JsonDocument.ParseValue(ref reader); JsonElement root = doc.RootElement; string partType = root.GetProperty("PartType").GetString(); Component instance = partType switch { nameof(Window) => new Window(), nameof(Engine) => new Engine(), nameof(Door) => new Door(), _ => new Component() }; // 反序列化为对应子类实例 return (Component)JsonSerializer.Deserialize(root.GetRawText(), instance.GetType(), options); } public override void Write(Utf8JsonWriter writer, Component value, JsonSerializerOptions options) { throw new NotImplementedException(); } }
反序列化时将转换器加入配置即可:
var jsonOptions = new JsonSerializerOptions { Converters = { new ComponentTypeConverter() } }; Product product = JsonSerializer.Deserialize<Product>(apiResponseJson, jsonOptions);
结果验证
反序列化完成后遍历product.Components列表即可看到:
PartType值为Window的元素是Window类实例,可直接访问Operation、Tinted属性PartType值为Engine的元素是Engine类实例,可直接访问Capacity、Cylinders、Layout属性PartType值为Door的元素是Door类实例,可直接访问DoorStyle属性
内容的提问来源于stack exchange,提问作者Chris Hammond
相关产品推荐
相关产品推荐

