如何用Newtonsoft.Json根据属性反序列化不同JSON到对应对象
解决方案
首先需要补全对应的数据结构类:
// 对应第一种JSON格式的结构 public class Structure1 { public int Id { get; set; } public string Result { get; set; } public string Comment { get; set; } } // 对应第二种JSON格式的结构 public class Structure2 { public int UserId { get; set; } public string PhoneNumber { get; set; } public string Message { get; set; } } // 你定义的信封类 public class EnvelopeObject { public Structure1 Structure1 { get; set; } public Structure2 Structure2 { get; set; } }
方法一:简便尝试法(无需自定义转换器)
直接尝试将JSON依次反序列化为Structure1和Structure2,成功的那个存入EnvelopeObject,失败则跳过。这种方式代码简单,适合格式差异明显的场景:
使用 Newtonsoft.Json(Json.NET)
public static EnvelopeObject DeserializeToEnvelope(string json) { var envelope = new EnvelopeObject(); // 尝试反序列为Structure1 try { var structure1 = JsonConvert.DeserializeObject<Structure1>(json); // 验证是否真的匹配(避免空值或默认值导致误判) if (structure1.Id != 0 || !string.IsNullOrEmpty(structure1.Result)) { envelope.Structure1 = structure1; return envelope; } } catch (JsonSerializationException) { // 反序列失败,继续尝试Structure2 } // 尝试反序列为Structure2 try { envelope.Structure2 = JsonConvert.DeserializeObject<Structure2>(json); return envelope; } catch (JsonSerializationException) { throw new InvalidOperationException("JSON格式不匹配Structure1或Structure2"); } }
方法二:自定义转换器(更优雅、性能更好)
通过自定义JSON转换器,直接解析JSON结构,判断属于哪种格式后再反序列化,适合复杂场景或高并发场景。
使用 Newtonsoft.Json 实现自定义转换器
public class EnvelopeObjectConverter : JsonConverter<EnvelopeObject> { public override EnvelopeObject ReadJson(JsonReader reader, Type objectType, EnvelopeObject existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObj = JObject.Load(reader); var envelope = new EnvelopeObject(); // 通过特征字段判断格式(比如Id是Structure1的独有字段) if (jsonObj.ContainsKey("Id")) { envelope.Structure1 = jsonObj.ToObject<Structure1>(serializer); } // 通过UserId判断是Structure2的格式 else if (jsonObj.ContainsKey("UserId")) { envelope.Structure2 = jsonObj.ToObject<Structure2>(serializer); } else { throw new JsonSerializationException("无法识别的JSON格式"); } return envelope; } public override void WriteJson(JsonWriter writer, EnvelopeObject value, JsonSerializer serializer) { // 序列化时只输出有值的结构 if (value.Structure1 != null) { serializer.Serialize(writer, value.Structure1); } else if (value.Structure2 != null) { serializer.Serialize(writer, value.Structure2); } else { writer.WriteNull(); } } }
使用转换器的两种方式:
- 给
EnvelopeObject添加特性:
[JsonConverter(typeof(EnvelopeObjectConverter))] public class EnvelopeObject { public Structure1 Structure1 { get; set; } public Structure2 Structure2 { get; set; } } // 反序列化时直接调用 var envelope = JsonConvert.DeserializeObject<EnvelopeObject>(json);
- 序列化时手动指定转换器:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new EnvelopeObjectConverter()); var envelope = JsonConvert.DeserializeObject<EnvelopeObject>(json, settings);
使用 System.Text.Json 实现自定义转换器
如果使用.NET Core/.NET 5+自带的System.Text.Json,转换器实现如下:
public class EnvelopeObjectConverter : JsonConverter<EnvelopeObject> { public override EnvelopeObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; var envelope = new EnvelopeObject(); if (root.TryGetProperty("Id", out _)) { envelope.Structure1 = JsonSerializer.Deserialize<Structure1>(root.GetRawText(), options); } else if (root.TryGetProperty("UserId", out _)) { envelope.Structure2 = JsonSerializer.Deserialize<Structure2>(root.GetRawText(), options); } else { throw new JsonException("无法识别的JSON格式"); } return envelope; } public override void Write(Utf8JsonWriter writer, EnvelopeObject value, JsonSerializerOptions options) { if (value.Structure1 != null) { JsonSerializer.Serialize(writer, value.Structure1, options); } else if (value.Structure2 != null) { JsonSerializer.Serialize(writer, value.Structure2, options); } else { writer.WriteNullValue(); } } }
使用方式:
var options = new JsonSerializerOptions(); options.Converters.Add(new EnvelopeObjectConverter()); var envelope = JsonSerializer.Deserialize<EnvelopeObject>(json, options);
两种方法对比
- 简便尝试法:代码量少,无需额外定义转换器;缺点是依赖异常捕获,性能略低,若两种结构有重叠字段可能出现误判。
- 自定义转换器:性能更优,判断逻辑精准,适合复杂场景或高并发场景;代码量稍多,但扩展性更好。
内容的提问来源于stack exchange,提问作者rjs52
相关产品推荐
相关产品推荐

