C#使用Newtonsoft.Json反序列化重名JSON字段的解决方法
问题根源
- 你获取的第三方JSON不符合常规规范:
for对象下存在两个同名的total、average键,分别对应对象和基础值两种不同类型,Newtonsoft.Json默认的反序列化逻辑无法适配这种重复键+类型不一致的场景,会抛出类型匹配异常。 - 你定义的
For类本身存在语法错误:C#不允许同一个类中定义多个同名(即使返回值类型不同)的属性,因此添加JsonProperty特性时会提示成员已存在。
解决方案
第一步:修正For类定义
首先删除重复的同名属性,为两类不同类型的total、average设置不同的属性名:
public class For { // 存储基础值类型的total、average public int TotalValue { get; set; } public string AverageValue { get; set; } // 存储对象类型的total、average public Total TotalObj { get; set; } public Average AverageObj { get; set; } public Minute minute { get; set; } public int home { get; set; } public int away { get; set; } } public class Total { public int home { get; set; } public int away { get; set; } public int total { get; set; } } public class Average { public string home { get; set; } public string away { get; set; } public string total { get; set; } }
第二步:选择适配的解析方式
方案1:JObject手动解析(适合单次解析场景)
直接将JSON解析为JObject,遍历属性手动处理重复键的赋值逻辑:
// jsonStr为第三方返回的完整JSON字符串 var rootJObj = JObject.Parse(jsonStr); var forNode = rootJObj["for"] as JObject; var forResult = new For(); foreach (var prop in forNode.Properties()) { switch (prop.Name) { case "total": if (prop.Value.Type == JTokenType.Object) forResult.TotalObj = prop.Value.ToObject<Total>(); else if (prop.Value.Type == JTokenType.Integer) forResult.TotalValue = prop.Value.Value<int>(); break; case "average": if (prop.Value.Type == JTokenType.Object) forResult.AverageObj = prop.Value.ToObject<Average>(); else if (prop.Value.Type == JTokenType.String) forResult.AverageValue = prop.Value.Value<string>(); break; case "minute": forResult.minute = prop.Value.ToObject<Minute>(); break; case "home": forResult.home = prop.Value.Value<int>(); break; case "away": forResult.away = prop.Value.Value<int>(); break; } }
方案2:自定义JsonConverter(适合批量解析场景)
如果需要多次解析该结构,可自定义转换器实现自动反序列化:
public class ForConverter : JsonConverter<For> { public override For ReadJson(JsonReader reader, Type objectType, For existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObj = JObject.Load(reader); var forResult = new For(); foreach (var prop in jObj.Properties()) { if (prop.Name == "total") { if (prop.Value.Type == JTokenType.Object) forResult.TotalObj = prop.Value.ToObject<Total>(serializer); else if (prop.Value.Type == JTokenType.Integer) forResult.TotalValue = prop.Value.Value<int>(); } else if (prop.Name == "average") { if (prop.Value.Type == JTokenType.Object) forResult.AverageObj = prop.Value.ToObject<Average>(serializer); else if (prop.Value.Type == JTokenType.String) forResult.AverageValue = prop.Value.Value<string>(); } else { serializer.Populate(prop.Value.CreateReader(), forResult); } } return forResult; } public override void WriteJson(JsonWriter writer, For value, JsonSerializer serializer) { // 不需要序列化为原JSON格式可直接抛出异常 throw new NotImplementedException(); } }
使用时传入转换器即可:
var forResult = JsonConvert.DeserializeObject<For>(jsonStr, new ForConverter());
内容的提问来源于stack exchange,提问作者Juan
相关产品推荐
相关产品推荐

