2016-06-20 4 views
2

は、このようなパケットに来ること、私はいくつかのJSONを持っていると言う配列に:デシリアライズインデックス付きプロパティ

{ 
    "LinkType1": "google", 
    "LinkUrl1": "https://plus.google.com/test", 
    "LinkShow1": 1, 

    "LinkType2": "facebook", 
    "LinkUrl2": "https://www.facebook.com/test", 
    "LinkShow2": 0, 

    "LinkType3": "linkedin", 
    "LinkUrl3": "http://www.linkedin.com/test", 
    "LinkShow3": 1, 

    "count": 3, 
    "errorCode": 0, 
    "errorMessage": "Success" 
} 

お知らせすべてが同じプロパティとしてではなく、その上にインデックスを使用して戻ってきますか?

私は、単一のプロパティではなく配列であるかのように、そのデータを逆シリアル化できることを望みます。これを下のクラスにデシリアライズするための最良の方法は何でしょうか?私はシリアライゼーションのためにNewtonsoft Jsonライブラリを使用しているので、それを使用するソリューションが優先されます。

public class LinksResult 
    { 
     public List<LinkData> Links { get; set; } 

     [JsonProperty("count")] 
     public int Count { get; set; } 

     [JsonProperty("errorCode")] 
     public int ErrorCode { get; set; } 

     [JsonProperty("errorMessage")] 
     public string ErrorMessage { get; set; } 
    } 

    public class LinkData 
    { 
     public string LinkType { get; set; } 
     public string LinkUrl { get; set; } 
     public bool LinkShow { get; set; } 
    } 

答えて

1

カスタムJsonConverterを使用すると、JSONデータを必要な構造にデシリアライズできます。ここでは、コンバータのコードがどのように見えるかを示します。

class LinksResultConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(LinksResult)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject obj = JObject.Load(reader); 
     LinksResult result = new LinksResult(); 
     result.Count = (int)obj["count"]; 
     result.ErrorCode = (int)obj["errorCode"]; 
     result.ErrorMessage = (string)obj["errorMessage"]; 
     result.Links = new List<LinkData>(); 

     for (int i = 1; i <= result.Count; i++) 
     { 
      string index = i.ToString(); 
      LinkData link = new LinkData(); 
      link.LinkType = (string)obj["LinkType" + index]; 
      link.LinkUrl = (string)obj["LinkUrl" + index]; 
      link.LinkShow = (int)obj["LinkShow" + index] == 1; 
      result.Links.Add(link); 
     } 

     return result; 
    } 

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

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

以下に示すように、ちょうどあなたのLinksResultクラスに[JsonConverter]属性を追加し、コンバータを使用します。 (JSONのプロパティ名と実際のクラスのメンバーとの間のマッピングは、コンバータによって直接処理されているので、あなたは、このアプローチに[JsonProperty]属性を必要としないことに注意してください。)

[JsonConverter(typeof(LinksResultConverter))] 
public class LinksResult 
{ 
    public List<LinkData> Links { get; set; } 
    public int Count { get; set; } 
    public int ErrorCode { get; set; } 
    public string ErrorMessage { get; set; } 
} 

を次に、あなたはこのようにデシリアライズすることができます:

LinksResult result = JsonConvert.DeserializeObject<LinksResult>(json); 

フィドル:https://dotnetfiddle.net/56b34H

+0

恐ろしい答え! –

+0

ありがとうございます。お役に立てて嬉しいです。 –

+0

ねえ、あなたの答えは、私があなたが作ったもののかなり素敵なジェネリックバージョンを作るのを助けました。私はスーパーが方向を感謝する! –

1

ブライアンの答えは非常に良かったし、それは私がなりたかった場所への道の80%を得ました。しかし、この種のパターンが多くの異なるオブジェクトで発生する場合、何度も何度も繰り返し使用することは、あまり良い実装ではありません。

もっと一般的なものを作りました。 「ページ」が持つインターフェース。

public interface IPage<TItem> 
{ 
    int Count { get; set; } 
    List<TItem> PageItems { get; set; } 
} 

次にページコンバータ自体。私はあなたがcontrol the serialization of capitalization with JsonSerializerSettingsので、最高の、選ばれたシリアライザまでではない私のコンバータをその細部を残すことができます考え出し

[JsonConverter(typeof(PageConverter<LinksResult, LinkData>))] 
public class LinksResult : IPage<LinkData> 
{ 
    public int Count { get; set; } 

    public List<LinkData> PageItems { get; set; } 
} 

public class PageConverter<TPage, TItem> : JsonConverter 
     where TPage : IPage<TItem>, new() 
     where TItem : new() 
{ 
    private readonly Regex _numberPostfixRegex = new Regex(@"\d+$"); 

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

    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(TPage)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var obj = serializer.Deserialize<JObject>(reader); 
     var page = new TPage(); 
     serializer.Populate(obj.CreateReader(), page); //Loads everything that isn't a part of the items. 
     page.PageItems = new List<TItem>(); 

     for (int i = 1; i <= page.Count; i++) 
     { 
      string index = i.ToString(); 

      //Find all properties that have a number at the end, then any of those that are the same number as the current index. 
      //Put those in a new JObject. 
      var jsonItem = new JObject(); 
      foreach (var prop in obj.Properties().Where(p => _numberPostfixRegex.Match(p.Name).Value == index)) 
      { 
       jsonItem[_numberPostfixRegex.Replace(prop.Name, "")] = prop.Value; 
      } 

      //Deserialize and add to the list. 
      TItem item = jsonItem.ToObject<TItem>(serializer); 
      page.PageItems.Add(item); 
     } 

     return page; 
    } 

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

は、それでは必要だということを、すべてのリンクが結果にそれを実装することです。

ここでフィダル:https://dotnetfiddle.net/7KhwYY

関連する問題