2017-11-29 8 views
1

JSON 배열이있는 유효한 JSON 개체가 있습니다. JSON 배열에는 중괄호가 없으며 쉼표로 구분 된 혼합 유형의 목록이 들어 있습니다. 나는이 목록의 목록을 테스트했습니다Json.Net을 사용하여 JSON 배열을 객체로 역 직렬화하는 방법은 무엇입니까?

class myModel 
{ 
    public int ID { get; set; } 
    public int Days { get; set; } 
    public DateTime StartDate { get; set; } 
    public DateTime EndDate { get; set; } 
    public string State { get; set; } 
    public string Page { get; set; } 
    public string Test { get; set; } 
    List<ChildModel> Rows { get; set; } 
} 

: 복잡한 배열의 목록을 가지고, 내가 JSON 구조를 반영하는 클래스를 생성 한

{ 
    "ID": 17, 
    "Days": 979, 
    "Start_Date": "10/13/2012", 
    "End_Date": "11/12/2012", 
    "State": "", 
    "Page": 1, 
    "Test": "Valid", 
    "ROWS": [ 
     [441210, "A", "12/31/2009", "OK", "Done", "KELLEY and Co'", "12/31/2009", "06/29/2010", "TEXAS", "Lawyers", 6, "", "<img src=\"/includes/images/Icon_done.gif\" border=\"0\" alt=\"Done\" title=\"Done\" />"], 
     [441151, "B", "12/31/2009", "No", "In-process", "Sage & Co", "12/31/2009", "06/29/2010", "CALIFORNIA", "Realtor", 6, "", "<img src=\"/includes/images/Icon_InProcess.gif\" border=\"0\" alt=\"In Process\" title=\"In Process\" />"] 
    ] 
} 

: 그것은 다음과 같습니다 또한이 같은

List<List<ChildModel>> Rows { get; set; } 

그리고 하위 모델 :

class ChildModel 
{ 
    public int ID { get; set; } 
    public string StatusId { get; set; } 
    public DateTime ContactDate { get; set; } 
    public string State { get; set; } 
    public string Status { get; set; } 
    public string CustomerName { get; set; } 
    public DateTime WorkStartDate { get; set; } 
    public DateTime WorkEndDate { get; set; } 
    public string Territory { get; set; } 
    public string CustType { get; set; } 
    public int JobOrder { get; set; } 
    public string Filler { get; set; } 
    public string Link { get; set; } 
} 
내 program.cs 파일에서

, 나는 이런 식으로 직렬화를 해제하고 있습니다 :이 프로그램을 실행하면

using (StreamReader r = new StreamReader(@"D:\01.json")) 
{ 
    myModel items = JsonConvert.DeserializeObject<myModel>(r.ReadToEnd()); 
} 

가, 자식 객체 (행)이 항상 null이다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

+0

그래서'ChildModel '이 객체가 아닌 배열로 직렬화된다고 말하는 겁니까? 직렬화가 통제에서 벗어 났습니까? –

+2

목록에있는 항목과 ChildModel 클래스 사이에 매핑이 없기 때문입니다. 디시리얼라이저는 모델의 어떤 속성에 어떤 값을 넣을 지 어떻게 알 수 있습니까? 가능한 경우 직렬화를 수정하거나 그렇지 않으면 사용자 정의 파서를 작성하고 목록에있는 데이터의 순서를 변경하지 말고기도하십시오. –

+1

해당 배열을'ChildModel'에 비 직렬화하려면 [C# JSON.NET - 비정상적인 데이터 구조를 사용하는 응답의 비 직렬화] (https://stackoverflow.com/q/39461518/3744182)의'ObjectToArrayConverter '을 사용할 수 있습니다. – dbc

답변

2

Json.Net에는 배열을 클래스에 자동으로 매핑하는 기능이 없습니다. 그렇게하려면 사용자 정의 JsonConverter이 필요합니다. 다음은 일반적인 변환기입니다. 사용자 정의 [JsonArrayIndex] 속성을 사용하여 클래스의 어떤 특성이 배열의 어떤 색인과 일치하는지 식별합니다. 이렇게하면 JSON이 변경되면 모델을 쉽게 업데이트 할 수 있습니다. 또한 필요없는 클래스의 속성 (예 : Filler)을 안전하게 생략 할 수 있습니다.

public class JsonArrayIndexAttribute : Attribute 
{ 
    public int Index { get; private set; } 
    public JsonArrayIndexAttribute(int index) 
    { 
     Index = index; 
    } 
} 

public class ArrayToObjectConverter<T> : JsonConverter where T : class, new() 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(T); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JArray array = JArray.Load(reader); 

     var propsByIndex = typeof(T).GetProperties() 
      .Where(p => p.CanRead && p.CanWrite && p.GetCustomAttribute<JsonArrayIndexAttribute>() != null) 
      .ToDictionary(p => p.GetCustomAttribute<JsonArrayIndexAttribute>().Index); 

     JObject obj = new JObject(array 
      .Select((jt, i) => 
      { 
       PropertyInfo prop; 
       return propsByIndex.TryGetValue(i, out prop) ? new JProperty(prop.Name, jt) : null; 
      }) 
      .Where(jp => jp != null) 
     ); 

     T target = new T(); 
     serializer.Populate(obj.CreateReader(), target); 

     return target; 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

아래 그림과 같이 당신이 당신의 ChildModel 클래스를 표시해야 컨버터를 사용하려면 : 여기

코드입니다

[JsonConverter(typeof(ArrayToObjectConverter<ChildModel>))] 
class ChildModel 
{ 
    [JsonArrayIndex(0)] 
    public int ID { get; set; } 
    [JsonArrayIndex(1)] 
    public string StatusId { get; set; } 
    [JsonArrayIndex(2)] 
    public DateTime ContactDate { get; set; } 
    [JsonArrayIndex(3)] 
    public string State { get; set; } 
    [JsonArrayIndex(4)] 
    public string Status { get; set; } 
    [JsonArrayIndex(5)] 
    public string CustomerName { get; set; } 
    [JsonArrayIndex(6)] 
    public DateTime WorkStartDate { get; set; } 
    [JsonArrayIndex(7)] 
    public DateTime WorkEndDate { get; set; } 
    [JsonArrayIndex(8)] 
    public string Territory { get; set; } 
    [JsonArrayIndex(9)] 
    public string CustType { get; set; } 
    [JsonArrayIndex(10)] 
    public int JobOrder { get; set; } 
    [JsonArrayIndex(12)] 
    public string Link { get; set; } 
} 

가 그럼 그냥 평소처럼 역 직렬화하고 같이 작동합니다 너는 원했어. 여기에 데모가 있습니다 : https://dotnetfiddle.net/n3oE3L

참고 : WriteJson을 구현하지 않았습니다. 따라서 모델을 JSON으로 다시 직렬화하면 다시 배열 형식으로 직렬화되지 않습니다. 대신 기본 객체 직렬화를 사용합니다.

+0

연장 방법은 매력처럼 작동했습니다. 감사. – SJaka

2

사용이 (... JSON 객체로

public class Rootobject 
{ 
    public int ID { get; set; } 
    public int Days { get; set; } 
    public string Start_Date { get; set; } 
    public string End_Date { get; set; } 
    public string State { get; set; } 
    public int Page { get; set; } 
    public string Test { get; set; } 
    public object[][] ROWS { get; set; } 
} 

을 데이터를 역 직렬화 ... 다음 원하는 대상 객체에 object[][]를 변환하는 유틸리티 함수 ...

을 만들 수 있습니다 편집 -> 선택하여 붙여 넣기 -> JSON 클래스)