【问题标题】:Deserializing response with an array使用数组反序列化响应
【发布时间】:2014-06-17 11:18:44
【问题描述】:

我正在使用 json.net,但在反序列化来自服务器的 json 响应时遇到问题我不知道应该为 errorsdata 两个属性使用什么数据类型。

除了这两个之外,有没有办法排除其他属性?服务器返回了很多我不感兴趣的数据。

我还让Data 类中的数据类型可以为空,因为当值未知时,服务器返回空值是解决这个问题的正确方法吗?

class DataFormat
{
    [JsonProperty("errors")]
    public Object Errors { get; set; }

    ...

    [JsonProperty("data")]
    public List<Data> Data { get; set; }    
}

class Data
{
    public DateTime Date { get; set; }
    public double? Open { get; set; }
    public double? High { get; set; }
    public double? Low { get; set; }
    public double? Last { get; set; }
    public double? Change { get; set; }
    public double? Settle { get; set; }
    public int? Volume { get; set; }
    public int? OpenInterest { get; set; }
}

我正在尝试反序列化 json

{
"errors": {},

...

"data": [
        ["2014-06-13", 2.9959, 3.0302, 2.9853, 0838, null, 2.9943, 27331.0, 51662.0],
        ["2014-06-12", 2.9092, 3.0017, 2.908, null, 0.0838, 2.9948, 35321.0, 47057.0]]
}

【问题讨论】:

    标签: c# json json.net deserialization


    【解决方案1】:

    要排除您不感兴趣的 JSON 属性,只需将这些成员排除在您的班级之外。 Json.Net 默认会忽略它们。

    如果 JSON 中的数字或日期值可以为 null,那么在您的类中使其可以为 null 正是处理它的正确方法。

    如果您不确定要制作Error 的类型,那么object 是可以的。你也可以在这里使用Dictionary&lt;string, object&gt;。如果您有 Error 数据的示例,那么您可以为它创建一个适当的类。

    您可以使用JsonConverter 将数组数据转换为您想要的对象格式。
    以下是转换器的外观:

    public class DataListConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Data);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken array = JToken.Load(reader);
            List<Data> list = new List<Data>();
            foreach (JArray data in array.Children<JArray>())
            {
                list.Add(new Data
                {
                    Date = data[0].ToObject<DateTime>(),
                    Open = data[1].ToObject<double?>(),
                    High = data[2].ToObject<double?>(),
                    Low = data[3].ToObject<double?>(),
                    Last = data[4].ToObject<double?>(),
                    Change = data[5].ToObject<double?>(),
                    Settle = data[6].ToObject<double?>(),
                    Volume = data[7].ToObject<int?>(),
                    OpenInterest = data[8].ToObject<int?>()
                });
            }
            return list;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    要使用它,只需将[JsonConverter] 属性添加到DataFormat 类中的Data 成员:

    class DataFormat
    {
        [JsonProperty("errors")]
        public Dictionary<string, object> Errors { get; set; }
    
        [JsonProperty("data")]
        [JsonConverter(typeof(DataListConverter))]
        public List<Data> Data { get; set; }
    }
    

    然后,您可以正常反序列化:

    DataFormat df = JsonConvert.DeserializeObject<DataFormat>(json);
    

    这是一个演示:

    class Program
    {
        static void Main(string[] args)
        {
            string json = @"
            {
                ""errors"": {},
                ""stuffToIgnore"" : ""foo bar"",
                ""data"": [
                        [""2014-06-13"", 2.9959, 3.0302, 2.9853, 0.0838, null, 2.9943, 27331.0, 51662.0],
                        [""2014-06-12"", 2.9092, 3.0017, 2.908, null, 0.0838, 2.9948, 35321.0, 47057.0]
                ]
            }";
    
            DataFormat df = JsonConvert.DeserializeObject<DataFormat>(json);
    
            foreach (Data item in df.Data)
            {
                Console.WriteLine("Date: " + item.Date.ToShortDateString());
                Console.WriteLine("Open: " + item.Open);
                Console.WriteLine("High: " + item.High);
                Console.WriteLine("Low: " + item.Low);
                Console.WriteLine("Last: " + item.Last);
                Console.WriteLine("Change: " + item.Change);
                Console.WriteLine("Settle: " + item.Settle);
                Console.WriteLine("Volume: " + item.Volume);
                Console.WriteLine("OpenInterest: " + item.OpenInterest);
                Console.WriteLine();
            }
        }
    }
    

    输出:

    Date: 6/13/2014
    Open: 2.9959
    High: 3.0302
    Low: 2.9853
    Last: 0.0838
    Change:
    Settle: 2.9943
    Volume: 27331
    OpenInterest: 51662
    
    Date: 6/12/2014
    Open: 2.9092
    High: 3.0017
    Low: 2.908
    Last:
    Change: 0.0838
    Settle: 2.9948
    Volume: 35321
    OpenInterest: 47057
    

    【讨论】:

    • 你几乎让我太容易了:) 你为你的答案付出了这么多努力,这正是我想要的,非常感谢!
    • 不错的一个。没想到。 +1
    【解决方案2】:

    Data 包含一个数组数组,而不是一个对象数组。

    class DataFormat
    {
        [JsonProperty("errors")]
        public Object Errors { get; set; }
    
        ...
    
        [JsonProperty("data")]
        public List<List<object>> Data { get; set; }    
    }
    

    【讨论】:

    • 是否可以将 List 替换为我将拥有正确数据类型的东西?现在我需要将“object{string}”转换为“DateTime”并将最后两个值转换为“int”。数据数组可以有大约 10k 行,我将使用多个“DataFormat”对象,需要程序尽可能快,所以它真的是最有效的方法吗?
    • 我不知道。您可以做一个肮脏的解决方案并使用string.Replace 或正则表达式将内部数组字符替换为对象字符。类似json.Replace("[\"", "{\"").Replace("],", "},");
    • @Hnus 您可以使用JsonConverter 来处理从嵌套JSON 数组到List&lt;Data&gt; 的所有数据转换。我添加了一个答案来展示如何做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-14
    • 2020-10-19
    • 2019-10-28
    • 1970-01-01
    相关资源
    最近更新 更多