处理在C#中包含不同类型的JSON字段

我必须阅读一个JSON文档,它有一个可以包含不同类型的字段。 例如,可以是long或整数数组。 我知道我需要使用自定义反序列化器,但不确定如何。 在下面的示例中,xx字段有时是long,否则是一个int数组。 任何有关如何处理此问题的帮助表示赞赏。

static void JsonTest() { const string json = @" { 'Code': 'XYZ', 'Response': { 'Type' : 'S', 'Docs': [ { 'id' : 'test1', 'xx' : 1 }, { 'id' : 'test2', 'xx' : [1, 2, 4, 8] }, ] } }"; A a; try { a = JsonConvert.DeserializeObject(json); } catch( Exception ex ) { Console.Error.WriteLine(ex.Message); } } public class A { public string Code; public TResponse Response; } public class TResponse { public string Type; public List Docs; } public class Doc { public string id; public int[] xx; } 

我的实现基于下面的建议(从int更改数组到long):

  [JsonConverter(typeof(DocConverter))] public class Doc { public string id; public long[] xx; } public class DocConverter : JsonConverter { public override bool CanWrite { get { return false; } } public override bool CanConvert( Type objectType ) { return typeof(Doc).IsAssignableFrom(objectType); } public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) { JObject item = JObject.Load(reader); Doc doc = new Doc(); doc.id = item["id"].ToObject(); if( item["xx"].Type == JTokenType.Long ) doc.xx = new [] { item["xx"].ToObject() }; else doc.xx = item["xx"].ToObject(); return doc; } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) { throw new NotImplementedException(); } } 

由于xx可以是longint数组,因此将Doc转换为类层次结构是有意义的。 (如果它是一个long或一个long s数组,那么将它们全部读入一个类是有意义的。)

您可以使用JsonConverter执行此JsonConverter ,如下所示:

 [JsonConverter(typeof(DocConverter))] public abstract class Doc { public string id; } [JsonConverter(typeof(NoConverter))] // Prevents infinite recursion when converting a class instance known to be of type DocSingle public class DocSingle : Doc { public long xx; } [JsonConverter(typeof(NoConverter))] // Prevents infinite recursion when converting a class instance known to be of type DocList public class DocList : Doc { public int[] xx; } public class DocConverter : JsonConverter { public override bool CanWrite { get { return false; } } public override bool CanConvert(Type objectType) { return typeof(Doc).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject item = JObject.Load(reader); if (item["xx"].Type == JTokenType.Integer) { return item.ToObject(); } else { return item.ToObject(); } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } public class NoConverter : JsonConverter { public override bool CanRead { get { return false; } } public override bool CanWrite { get { return false; } } public override bool CanConvert(Type objectType) { return false; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

更新

顺便说一句,如果您愿意简化数据模型以说xx可以是单个longlong s数组,则可以按如下方式简化代码:

 [JsonConverter(typeof(DocConverter))] public sealed class Doc { public string id; public long[] xx; } public class DocConverter : JsonConverter { public override bool CanWrite { get { return true; } } public override bool CanConvert(Type objectType) { return typeof(Doc).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject item = JObject.Load(reader); var doc = new Doc(); JToken id = item["id"]; if (id != null) doc.id = id.ToString(); JToken xx = item["xx"]; if (xx != null) { if (xx.Type == JTokenType.Integer) { var val = (long)xx; doc.xx = new long[] { val }; } else if (xx.Type == JTokenType.Array) { var val = xx.ToObject(); doc.xx = val; } else { Debug.WriteLine("Unknown type of JToken for \"xx\": " + xx.ToString()); } } return doc; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var doc = (Doc)value; writer.WriteStartObject(); writer.WritePropertyName("id"); writer.WriteValue(doc.id); var xx = doc.xx; if (xx != null) { writer.WritePropertyName("xx"); if (xx.Length == 1) { writer.WriteValue(xx[0]); } else { writer.WriteStartArray(); foreach (var x in xx) { writer.WriteValue(x); } writer.WriteEndArray(); } } writer.WriteEndObject(); } } 

你有一个字符串,尝试json.Contains(“’Type’:’S’”)。 然后将其反序列化为适当的模型。