2016-06-08 131 views
2

我有一個JSON文件中像這樣單獨提供:反序列化JSON陣列與鍵的字典從JSON

{ 
    "price": ["123.50", "124.6", "126.30"], 
    "order": ["23", "30", "20"] 
} 

我想,以填補我的對象Product

public class Product { 
    public Dictionary<string, Object> priceInfo; 
    public Dictionary<string, Object> orderInfo; 
} 

我有各JSON對象每個值的描述(這裏有數組)可能在Product類中,例如:

String[] defPriceInfo = {"price", "avgprice", "maxprice"}; 

最後,我將訪問Product對象的這些數值與priceInfo.TryGetValue("avgprice", ...),它將返回給我,我中搜索堆棧溢出值

124.6

,但我沒有找到一個類似的問題。 其實我試圖覆蓋JsonConverter.ReadJson,但它沒有奏效;問題是我想要的個性化「鑰匙」。

編輯1:我有這個ReadJson()方法,但這是錯誤的。

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      object res = new Object(); 
      var tokenType = reader.TokenType; 
      if (tokenType == JsonToken.StartObject) 
      { 
       object obj = serializer.Deserialize(reader); 
       res = new Dictionary<string, string>(); 
      } 
      else if (tokenType == JsonToken.StartArray) 
      { 
       res = serializer.Deserialize(reader); 
      } 
      return res; 
     } 
+0

你說的*也許在Item類意味着*?你的問題中沒有'Item'類。你是不是指'Product'類?如果是這樣,你能給出一個[完整的例子](https://stackoverflow.com/help/mcve)你想要以這種方式序列化和反序列化的類,以及你在'ReadJson()'中嘗試過的東西嗎? – dbc

+0

對不起,我改變了項目的產品錯誤。我的意思是說「也許」不是最好的解決方案。但實際上我看到的只是解決方案。我也想用文件加載信息。我會發布我的嘗試。我試過的解決方案的問題是,我不知道如何在我的課程中爲我讀取的每個值傳遞「鍵」描述符。 – Neyoh

+0

@dbc我加了我的例子,但這是完全錯誤的。我不明白這是如何工作的 – Neyoh

回答

3

以下是一種使用自定義JsonConverter作爲通用解決方案的方法。這個想法是,你建立一個公共的,靜態的,只讀的字符串數組,包含你想要處理的每個字典的關鍵字,然後用[JsonConverter]屬性標記每個字典字段,該屬性指定在哪裏找到包含關鍵字數組的靜態字段。轉換器然後使用指定的鍵從JSON數組填充字典。 (請注意,如果JSON數組屬性的名字從你的類字典成員名稱不同,你還需要一個[JsonProperty]屬性綁在一起。)

這裏是你如何將它設置你的榜樣Product類:

public class Product 
{ 
    public static readonly string[] defPriceInfo = { "price", "avgprice", "maxprice" }; 
    public static readonly string[] defOrderInfo = { "first", "second", "third" }; 

    [JsonProperty("price")] 
    [JsonConverter(typeof(ArrayToDictionaryConverter), typeof(Product), "defPriceInfo")] 
    public Dictionary<string, object> priceInfo; 

    [JsonProperty("order")] 
    [JsonConverter(typeof(ArrayToDictionaryConverter), typeof(Product), "defOrderInfo")] 
    public Dictionary<string, object> orderInfo; 
} 

這裏是自定義ArrayToDictionaryConverter代碼:

class ArrayToDictionaryConverter : JsonConverter 
{ 
    private string[] keysArray; 

    public ArrayToDictionaryConverter(Type containingObjectType, string keysArrayFieldName) 
    { 
     FieldInfo field = containingObjectType.GetField(keysArrayFieldName); 
     if (field == null) 
      throw new Exception("Could not find " + keysArrayFieldName + " field on type " + containingObjectType.Name + "."); 
     if (!field.Attributes.HasFlag(FieldAttributes.Static) || field.FieldType != typeof(String[])) 
      throw new Exception("The " + keysArrayFieldName + " field on " + containingObjectType.Name + " must be declared as static string[]."); 
     keysArray = (string[])field.GetValue(null); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Dictionary<string, object>)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JArray array = JArray.Load(reader); 
     Dictionary<string, object> dict = new Dictionary<string, object>(); 

     for (int i = 0; i < array.Count; i++) 
     { 
      string key = i < keysArray.Length ? keysArray[i] : "key" + i; 
      dict.Add(key, (string)array[i]); 
     } 

     return dict; 
    } 

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

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

這裏是在一個快速演示它是如何工作:

using System; 
using System.Collections.Generic; 
using System.Reflection; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Linq; 

public class Program 
{ 
    public static void Main() 
    { 
     string json = @" 
      { 
       ""price"": [""123.50"", ""124.6"", ""126.30""], 
       ""order"": [""23"", ""30"", ""20""] 
      }"; 

     try 
     { 
      Product prod = JsonConvert.DeserializeObject<Product>(json); 
      foreach (var kvp in prod.priceInfo) 
      { 
       Console.WriteLine(kvp.Key + ": " + kvp.Value); 
      } 
      foreach (var kvp in prod.orderInfo) 
      { 
       Console.WriteLine(kvp.Key + ": " + kvp.Value); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      if (e.InnerException != null) Console.WriteLine(e.InnerException.Message); 
     } 
    } 
} 

輸出:

price: 123.50 
avgprice: 124.6 
maxprice: 126.30 
first: 23 
second: 30 
third: 20 
+0

謝謝,但我有一個錯誤,因爲「JsonConverterAttribute構造函數沒有3個參數」 – Neyoh

+1

支持['JsonConverterAttribute'構造函數]上的其他參數(http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonConverterAttribute__ctor_1 .htm)是在[Json.Net版本6.0.6](https://github.com/JamesNK/Newtonsoft.Json/releases/tag/6.0.6)(2014年10月20日)中添加的。如果您使用的是舊版本,則需要升級。 [當前版本](https://github.com/JamesNK/Newtonsoft.Json/releases)截至目前爲8.0.3。 –

0

你可以先反序列化JSON到POCO,例如使用這樣的類做到這一點:

public class TempProduct 
{ 
    public Price price {get; set;} 
    public Order order {get; set;} 

    public class Price 
    { 
    public string price {get; set;} 
    public string avgprice {get; set;} 
    public string maxprice {get; set;} 
    } 

    public class Order 
    { 
    public string orderType1 {get; set;} 
    public string orderType2 {get; set;} 
    public string orderType3 {get; set;} 
    } 
} 

然後你可以從這個例如填充您的產品類別

var prod = new Product(); 

prod.priceInfo = new Dictionary<string,Object>(); 
prod.priceInfo.Add("price", tempProd.price.price); 
prod.priceInfo.Add("avgprice", tempProd.price.avgprice); 
prod.priceInfo.Add("maxprice", tempProd.price.maxprice); 
+0

我不確定此解決方案是否適合我的問題。我不希望乘上這些類,因爲我想要一些通用的東西。 – Neyoh