使用 Json.net 反序列化 JSON 对象数组

Posted

技术标签:

【中文标题】使用 Json.net 反序列化 JSON 对象数组【英文标题】:Deserializing JSON Object Array with Json.net 【发布时间】:2013-08-14 01:57:09 【问题描述】:

我正在尝试使用一个 API,该 API 使用以下示例结构来返回其返回的 json

[
   
      "customer":
         "first_name":"Test",
         "last_name":"Account",
         "email":"test1@example.com",
         "organization":"",
         "reference":null,
         "id":3545134,
         "created_at":"2013-08-06T15:51:15-04:00",
         "updated_at":"2013-08-06T15:51:15-04:00",
         "address":"",
         "address_2":"",
         "city":"",
         "state":"",
         "zip":"",
         "country":"",
         "phone":""
      
   ,
   
      "customer":
         "first_name":"Test",
         "last_name":"Account2",
         "email":"test2@example.com",
         "organization":"",
         "reference":null,
         "id":3570462,
         "created_at":"2013-08-12T11:54:58-04:00",
         "updated_at":"2013-08-12T11:54:58-04:00",
         "address":"",
         "address_2":"",
         "city":"",
         "state":"",
         "zip":"",
         "country":"",
         "phone":""
      
   
]

JSON.net 可以很好地处理类似以下结构的东西


    "customer": 
        ["field1" : "value", etc...],
        ["field1" : "value", etc...],
    

但我不知道如何让它对提供的结构感到满意。

使用默认的 JsonConvert.DeserializeObject(content) 可以得到正确数量的客户,但所有数据均为空。

对 CustomerList(如下)执行操作会导致“无法反序列化当前 JSON 数组”异常

public class CustomerList

    public List<Customer> customer  get; set; 

想法?

【问题讨论】:

这能回答你的问题吗? Deserialize JSON with C# 【参考方案1】:

您可以创建一个新模型来反序列化您的 JSON CustomerJson

    public class CustomerJson
    
        [JsonProperty("customer")]
        public Customer Customer  get; set; 
    

    public class Customer
    
        [JsonProperty("first_name")]
        public string Firstname  get; set; 

        [JsonProperty("last_name")]
        public string Lastname  get; set; 

        ...
    

您可以轻松地反序列化您的 JSON:

JsonConvert.DeserializeObject<List<CustomerJson>>(json);

文档:Serializing and Deserializing JSON

【讨论】:

JsonConvert.DeserializeObject>(json);非常适合字符串输入。 DeserializeObject() 在运行 ARM 的 android 手机上运行缓慢。对于这种情况有更好的解决方案吗? 尝试使用 JObject JObject.Parse(json);进行导航【参考方案2】:

对于那些不想创建任何模型的人,使用以下代码:

var result = JsonConvert.DeserializeObject<
  List<Dictionary<string, 
    Dictionary<string, string>>>>(content);

注意:这不适用于 您的 JSON 字符串。这不是任何 JSON 结构的通用解决方案。

【讨论】:

【参考方案3】:

使用接受的答案,您必须使用Customers[i].customer 访问每条记录,并且您需要一个额外的CustomerJson 类,这有点烦人。如果您不想这样做,可以使用以下方法:

public class CustomerList

    [JsonConverter(typeof(MyListConverter))]
    public List<Customer> customer  get; set; 

请注意,我使用的是List&lt;&gt;,而不是数组。现在创建以下类:

class MyListConverter : JsonConverter

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        var token = JToken.Load(reader);
        var list = Activator.CreateInstance(objectType) as System.Collections.IList;
        var itemType = objectType.GenericTypeArguments[0];
        foreach (var child in token.Values())
        
            var childToken = child.Children().First();
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(childToken.CreateReader(), newObject);
            list.Add(newObject);
        
        return list;
    

    public override bool CanConvert(Type objectType)
    
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

【讨论】:

【参考方案4】:

对上述内容稍作修改。我验证的 Json 格式是


    mycollection:[
              
               property0:value,
               property1:value,
             ,
                
               property0:value,
               property1:value,
             
           ]

         
       

使用 AlexDev 的响应,我这样做了循环每个孩子,从中创建阅读器

 public partial class myModel

    public static List<myModel> FromJson(string json) => JsonConvert.DeserializeObject<myModelList>(json, Converter.Settings).model;


 public class myModelList 
    [JsonConverter(typeof(myModelConverter))]
    public List<myModel> model  get; set; 



class myModelConverter : JsonConverter

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        var token = JToken.Load(reader);
        var list = Activator.CreateInstance(objectType) as System.Collections.IList;
        var itemType = objectType.GenericTypeArguments[0];
        foreach (var child in token.Children())  //mod here
        
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(child.CreateReader(), newObject); //mod here
            list.Add(newObject);
        
        return list;
    

    public override bool CanConvert(Type objectType)
    
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();


【讨论】:

【参考方案5】:

从JC_VA进一步修改,取他所有的,把MyModelConverter替换成...

public class MyModelConverter : JsonConverter

    //objectType is the type as specified for List<myModel> (i.e. myModel)
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        var token = JToken.Load(reader); //json from myModelList > model
        var list = Activator.CreateInstance(objectType) as System.Collections.IList; // new list to return
        var itemType = objectType.GenericTypeArguments[0]; // type of the list (myModel)
        if (token.Type.ToString() == "Object") //Object
        
            var child = token.Children();
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(token.CreateReader(), newObject);
            list.Add(newObject);
        
        else //Array
        
            foreach (var child in token.Children())
            
                var newObject = Activator.CreateInstance(itemType);
                serializer.Populate(child.CreateReader(), newObject);
                list.Add(newObject);
            
        
        return list;

    

    public override bool CanConvert(Type objectType)
    
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

这应该适用于 json

myModelList
 model: [ ... object ... ]

myModelList
 model:  ... object ... 

它们最终都会像被解析一样被解析

myModelList
 model: [ ... object ... ]

【讨论】:

以上是关于使用 Json.net 反序列化 JSON 对象数组的主要内容,如果未能解决你的问题,请参考以下文章

使用 Json.NET 反序列化复杂对象

使用 DataContractSerializer 发送反序列化的 Json.net 对象时出错

使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON.net 的json的序列化与反序列化

.Net使用Newtonsoft.Json.dll(JSON.NET)对象序列化成json反序列化json示例教程

Json.Net以索引为名称反序列化JSON对象[重复]

检测反序列化的对象是不是缺少 Json.NET 中 JsonConvert 类的字段