基于Newtonsoft.Json实现动态结构content_description节点的分模型反序列化
Newtonsoft.Json 多结构节点自动匹配反序列化实现方案
针对同一个JSON节点存在两种互斥结构、需要自动匹配对应独立模型、未匹配字段保持null的需求,可通过自定义JsonConverter实现结构自动分发,无需将所有跨结构字段合并到同一个DTO中。
第一步:拆分独立的结构模型
按照两种实际的JSON结构,分别定义独立C#类,每个类仅包含对应结构下的专属字段,实现职责隔离:
// 对应第一种结构:多长度内容简介模型 public class ContentSynopsisDescription { public string language { get; set; } public string short_synapsis { get; set; } public string medium_synopsis { get; set; } public string long_synopsis { get; set; } public string oneliner { get; set; } // 原合并类中涉及的季、集相关简介字段,可直接按需添加到本类中 } // 对应第二种结构:元数据描述模型 public class ContentMetadataDescription { public string text { get; set; } public string category { get; set; } public string level { get; set; } public string source { get; set; } }
第二步:实现结构自动判别与分发逻辑
两种结构的字段完全不重叠,可通过特征字段快速判断节点类型,将节点内容映射到对应模型,同时将未匹配的模型字段置为null。
自定义分发Converter
public class ContentDescriptionDispatchingConverter : JsonConverter { // 仅需要反序列化读取逻辑,关闭默认序列化写入通道 public override bool CanWrite => false; public override bool CanConvert(Type objectType) { // 仅对根媒体模型生效 return objectType == typeof(RootMediaModel); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // 读取整个根JSON节点为JObject,方便结构判断 var rootObject = JObject.Load(reader); var model = new RootMediaModel(); // 先正常填充根节点下的通用字段(title、series) serializer.Populate(rootObject.CreateReader(), model); // 取出content_description节点 var contentNode = rootObject["content_description"] as JObject; if (contentNode == null) return model; // 基于特征字段做结构判断 // 匹配第一种简介结构:存在language、medium_synopsis专属字段 if (contentNode["language"] != null && contentNode["medium_synopsis"] != null) { model.SynopsisContentDescription = contentNode.ToObject<ContentSynopsisDescription>(serializer); model.MetadataContentDescription = null; } // 匹配第二种元数据结构:存在category、source专属字段 else if (contentNode["category"] != null && contentNode["source"] != null) { model.MetadataContentDescription = contentNode.ToObject<ContentMetadataDescription>(serializer); model.SynopsisContentDescription = null; } return model; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
定义根模型
给根模型标记自定义Converter,同时定义两个独立的content_description对应字段:
[JsonConverter(typeof(ContentDescriptionDispatchingConverter))] public class RootMediaModel { public TitleInfo title { get; set; } public SeriesInfo series { get; set; } // 两个独立字段,匹配到对应结构时自动填充,未匹配的字段保持null public ContentSynopsisDescription SynopsisContentDescription { get; set; } public ContentMetadataDescription MetadataContentDescription { get; set; } } // 对应JSON中title节点的辅助类 public class TitleInfo { public string title { get; set; } public string episode_title { get; set; } } // 对应JSON中series节点的辅助类 public class SeriesInfo { public string season { get; set; } public string episode { get; set; } }
第三步:反序列化调用
注意:原示例JSON中
series节点结束的大括号后缺少逗号,实际使用时需要保证JSON语法符合规范,避免反序列化失败。
调用方式和Newtonsoft.Json原生逻辑完全兼容,不需要额外调整参数:
var model = JsonConvert.DeserializeObject<RootMediaModel>(jsonContent);
实现效果
- 当content_description节点为第一种结构时,
SynopsisContentDescription会被完整填充,MetadataContentDescription自动为null - 当content_description节点为第二种结构时,
MetadataContentDescription会被完整填充,SynopsisContentDescription自动为null - 后续如果新增其他结构的content_description,只需要新增对应独立模型,在Converter的判别逻辑中增加对应分支即可,不需要修改现有结构定义
- 判别逻辑可根据实际场景灵活调整,比如两种结构存在公共字段时,可通过多字段组合校验、字段值类型判断等方式提升识别准确率
内容的提问来源于stack exchange,提问作者Aegonek
相关产品推荐
相关产品推荐

