2016-06-08 89 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