Deserializing JSON Object Array ด้วย Json.net


118

ฉันพยายามใช้ 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 (เนื้อหา) ทำให้จำนวนลูกค้าถูกต้อง แต่ข้อมูลทั้งหมดเป็นค่าว่าง

การทำบางอย่างใน CustomerList (ด้านล่าง) จะทำให้เกิดข้อยกเว้น "ไม่สามารถแยกส่วนของอาร์เรย์ JSON ปัจจุบัน"

public class CustomerList
{
    public List<Customer> customer { get; set; }
}

คิด?


สิ่งนี้ตอบคำถามของคุณหรือไม่? Deserialize JSON ด้วย C #
GetFookedWeeb

คำตอบ:


187

คุณสามารถสร้างโมเดลใหม่เพื่อ Deserialize 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; }

    ...
}

และคุณสามารถ deserialize json ของคุณได้อย่างง่ายดาย:

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

หวังว่าจะช่วยได้!

เอกสารประกอบ: Serializing และ Deserializing JSON


1
ขอบคุณ คิดถึงปัญหานี้ ตามที่คุณตอบก่อนคำตอบของคุณได้รับการยอมรับ
Shawn C.

2
JsonConvert.DeserializeObject <รายการ <CustomerJson >> (JSON); ทำงานได้อย่างสมบูรณ์แบบสำหรับอินพุตสตริง
Markel Mairs

DeserializeObject()ช้าบนโทรศัพท์ Android ที่ใช้ ARM ทางออกที่ดีกว่าสำหรับกรณีนั้นหรือไม่?
ธ เดช

1
ลองนำทางด้วย JObjectJObject.Parse(json);
Joffrey Kern

47

สำหรับผู้ที่ไม่ต้องการสร้างโมเดลใด ๆ ให้ใช้รหัสต่อไปนี้:

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

หมายเหตุ: ใช้ไม่ได้กับสตริง JSON ของคุณ นี่ไม่ใช่วิธีแก้ปัญหาทั่วไปสำหรับโครงสร้าง JSON ใด ๆ


10
นี่เป็นทางออกที่แย่มาก หากคุณไม่ต้องการสร้างโมเดลให้ใช้var result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);
a11smiles

1
@ a11smiles โปรดอธิบายว่าเหตุใดจึงเป็นทางออกที่แย่มาก
Tyler Long

2
ขั้นแรกการจัดสรรหน่วยความจำที่ไม่จำเป็นสำหรับการIEnumerableใช้งานประเภทต่างๆ(3 เทียบกับ List <Tuple>) ประการที่สองวิธีการแก้ปัญหาของคุณหมายถึงคีย์ที่แตกต่างกัน 2 คีย์ - 1 สำหรับแต่ละพจนานุกรม จะเกิดอะไรขึ้นถ้าลูกค้าหลายคนมีชื่อเดียวกัน? จะไม่มีความแตกต่างในคีย์ วิธีแก้ปัญหาของคุณไม่ได้คำนึงถึงความขัดแย้งนี้
a11smiles

2
@ a11smiles ลูกค้าแต่ละรายเป็นพจนานุกรมแยกกัน ดังนั้นจะไม่มีปัญหาใด ๆ แม้ว่าจะมีลูกค้าหลายคนที่มีชื่อเดียวกัน
Tyler Long

1
@ a11smiles ฉันสงสัยว่าทำไมคุณถึงคิดว่าvar result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);จะได้ผล เห็นได้ชัดว่ามันใช้ไม่ได้
Tyler Long

1

การใช้คำตอบที่ได้รับการยอมรับคุณต้องเข้าถึงแต่ละระเบียนโดยใช้Customers[i].customerและคุณต้องมีCustomerJsonชั้นเรียนพิเศษซึ่งน่ารำคาญเล็กน้อย หากคุณไม่ต้องการทำเช่นนั้นคุณสามารถใช้สิ่งต่อไปนี้:

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

โปรดทราบว่าฉันกำลังใช้ a List<>ไม่ใช่ Array ตอนนี้สร้างคลาสต่อไปนี้:

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();
}

1

การปรับเปลี่ยนเล็กน้อยกับสิ่งที่ระบุไว้ข้างต้น รูปแบบ Json ของฉันซึ่งตรวจสอบได้คือ

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

         }
       }

ด้วยการใช้คำตอบของ AlexDev ฉันทำ Looping เด็กแต่ละคนสร้างผู้อ่านจากมัน

 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();

}

0

แก้ไขเพิ่มเติมจาก 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 ... }]
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.