【问题标题】:Deserialize Dictionary with unknown keys with RestSharp使用 RestSharp 反序列化具有未知键的字典
【发布时间】:2017-05-04 20:44:32
【问题描述】:

我目前正在获取一个形状类似于以下内容的 JSON 对象:

{
 more data here...
  "years": {
    "value": 2013,
    "item1": {
      "total": 0.1044,
      "Low": 0.0143,
      "Mid": 0.1044,
      "High": 0.3524,
      "min": 0.0143,
      "max": 0.3524,
    },
    "item2": {
      "total": 0.1702,
      "Low": 0.167,
      "Mid": 0.1702,
      "High": 0.1737,
      "min": 0.167,
      "max": 0.1737,
    },...
  }
}

不幸的是,我无法控制 JSON 的形状。

我正在尝试让 RestSharp 将其反序列化为一个对象,其中 Item1、Item2 和其余部分填充到一个字典中我目前有以下代码:

public class Year
{
    public int Value { get; set; }
    public Dictionary<string, Data> Data { get; set; }
}

public class Data
{
    public decimal Total { get; set; }
    public decimal Low { get; set; }
    public decimal Mid { get; set; }
    public decimal High { get; set; }
    public decimal Min { get; set; }
    public decimal Max { get; set; }
}

我希望Item1,Item2等成为Dictionary的键,下面的值填充Data类作为Dictionary的值。但目前它不起作用(我的结构的其余部分是,它只是最里面的部分)。我只是接近结构错误吗?我想避免为 Item1 和 Item2 创建一个特定的类。

【问题讨论】:

    标签: c# restsharp json-deserialization


    【解决方案1】:

    您可以使用自定义JsonConverter

    public class YearConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Year);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var obj = JObject.Load(reader);
    
            int year = (int)obj["value"];
            var data = new Dictionary<string, Data>();
    
            foreach (var dataItem in obj.Children()
                .OfType<JProperty>()
                .Where(p => p.Name.StartsWith("item")))
            {
                data.Add(dataItem.Name, dataItem.Value.ToObject<Data>());
            }
    
            return new Year
            {
                Value = year,
                Data = data
            };
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    用转换器装饰你的Year 类:

    [JsonConverter(typeof(YearConverter))]
    public class Year
    {
        public int Value { get; set; }
        public Dictionary<string, Data> Data { get; set; }
    }
    

    这样使用,例如:

    class Program
    {
        static void Main(string[] args)
        {
            string json = @"
    {
      ""value"": 2013,
      ""item1"": {
        ""total"": 0.1044,
        ""Low"": 0.0143,
        ""Mid"": 0.1044,
        ""High"": 0.3524,
        ""min"": 0.0143,
        ""max"": 0.3524,
      },
      ""item2"": {
        ""total"": 0.1702,
        ""Low"": 0.167,
        ""Mid"": 0.1702,
        ""High"": 0.1737,
        ""min"": 0.167,
        ""max"": 0.1737,
      }
    }";
            var years = JsonConvert.DeserializeObject<Year>(json);
        }
    }
    

    【讨论】:

      【解决方案2】:

      步骤: 1。始终以合乎逻辑的方式塑造您的 JSON 对象

      如果您以更合乎逻辑的方式重组 json 对象,则此问题将更容易处理。现在,您有 n 个与“值”处于同一级别的数据对象,并且您正在动态更改它们的属性名称。

      就个人而言,我会像这样重塑 json:

      {
         "years":[
            {
               "value":2013,
               "data":[
                  {
                     "name":"item1",
                     "total":0.1044,
                     "Low":0.0143,
                     "Mid":0.1044,
                     "High":0.3524,
                     "min":0.0143,
                     "max":0.3524
                  },
                  {
                     "name":"item2",
                     "total":0.1702,
                     "Low":0.167,
                     "Mid":0.1702,
                     "High":0.1737,
                     "min":0.167,
                     "max":0.1737
                  }
               ]
            }
         ]
      }
      

      第 2 步:将 Newtonsoft.Json 属性添加到您的类中

      这样可以轻松反序列化

      public class Base
      {
          [JsonProperty("years")]
          public List<Year> years { get; set; }
      }
      
          public class Year
          {
              [JsonProperty("value")]
              public int Value { get; set; }
      
              [JsonProperty("data")]
              public List<Data> data { get; set; }
          }
      
          public class Data
      {
              [JsonProperty("name")]
          public string name { get; set; }
              [JsonProperty("total")]
              public decimal Total { get; set; }
              [JsonProperty("Low")]
              public decimal Low { get; set; }
              [JsonProperty("Mid")]
              public decimal Mid { get; set; }
              [JsonProperty("High")]
              public decimal High { get; set; }
              [JsonProperty("min")]
              public decimal Min { get; set; }
              [JsonProperty("max")]
              public decimal Max { get; set; }
          }
      

      第 3 步:反序列化

      Base myYears = JsonConvert.DeserializeObject<Base>(myJsonString);
      

      【讨论】:

      • 感谢您的意见。我可能应该提到我无法控制 JSON 格式,我将对其进行编辑。我试图避免引入另一个库,但我会牢记 JSON.Net。
      • 你可以将传入的 JSON 映射成你想要的样子,这样你就可以轻松地重组
      • 我强调重构它,因为我认为该模型实际上在逻辑上被破坏了。在“年”下面,有一堆属性、未知名称,其中一个是字符串,其余的是数据对象。我们不知道名称将是什么,因此我们甚至无法知道将其绑定到哪个 C# 变量名称。另一种方法是使用这个:newtonsoft.com/json/help/html/… 我认为您可以编写自定义规则并覆盖分配以使其看起来像您想要的那样。
      • 我很好奇如何在不反序列化的情况下重新映射 JSON。您是否建议在使用前操作 JSON 字符串以使其更易于解析?那不会面临类似的挑战吗?
      • 我发布的链接显示了如何为 Json 对象方法编写自定义规则,您可以在其中覆盖常规的 getter 和 setter,因此理论上您应该能够将其与 JsonProperty 属性结合以完全序列化,我相信。这是我希望你使用 JavaScript 而不是 .NET 的时候之一!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多