首页 > 解决方案 > 蜡烛数组从响应到历史对象列表的转换。正文中的其他细节

问题描述

我有以下对象从其中一个 API 获得返回。

{{
  "status": "success",
  "data": {
    "candles": [
      [
        "2020-11-01T18:30:00+00:00",
        1065,
        1079.95,
        1051.1,
        1072.3,
        7183119
      ],
      [
        "2020-11-02T18:30:00+00:00",
        1072,
        1079.4,
        1057.5,
        1062.55,
        7204782
      ],]
  }
}}

我想将蜡烛数据转换成List<Historical> 这是我尝试过的

foreach (ArrayList item in historicalData["data"]["candles"])
                historicals.Add(new Historical(item));

但这给了我以下错误:

Cannot convert type 'Newtonsoft.Json.Linq.JArray' to 'System.Collections.ArrayList

我尝试使用 JsonConvert.DeserializeObject 使用以下代码将字符串直接转换为对象:

foreach (var item in historicalData["data"]["candles"]) {
                var historical = JsonConvert.DeserializeObject<Historical>(item.ToString());

但是得到了这个错误:

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'QuantConnect.Brokerages.Zerodha.Messages.Historical' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '', line 1, position 1.

历史定义:

public struct Historical
    {
        public Historical(dynamic data)
        {
            TimeStamp = Convert.ToDateTime(data[0], CultureInfo.InvariantCulture);
            Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
            High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
            Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
            Close = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture);
            Volume = Convert.ToUInt32(data[5], CultureInfo.InvariantCulture);
            OI = data.Count > 6 ? Convert.ToUInt32(data[6], CultureInfo.InvariantCulture) : 0;
        }

        public DateTime TimeStamp { get; }
        public decimal Open { get; }
        public decimal High { get; }
        public decimal Low { get; }
        public decimal Close { get; }
        public UInt32 Volume { get; }
        public UInt32 OI { get; }
    }

有没有一种正确/优雅的方式让它发挥作用。还有什么我在这里错过了什么?

标签: c#arraysjsonfacebook-c#-sdk

解决方案


  1. 主要问题是这不是有效的 json。但是,让我们修复它并假设它是正确的。如果这是您从某些资源中获得的信息,我建议您联系他们并投诉。
  2. 有很多方法可以做到这一点。既然你使用了 JTokens,我会给你一个类似的答案。

给定

{
   "status":"success",
   "data":{
      "candles":[
         [
            "2020-11-01T18:30:00+00:00",
            1065,
            1079.95,
            1051.1,
            1072.3,
            7183119
         ],
         [
            "2020-11-02T18:30:00+00:00",
            1072,
            1079.4,
            1057.5,
            1062.55,
            7204782
         ]
      ]
   }
}

public class Historical
{
   public DateTime TimeStamp { get; set; }
   public decimal Open { get; set; }
   public decimal High { get; set; }
   public decimal Low { get; set; }
   public decimal Close { get; set; }
   public UInt32 Volume { get; set; }
   public UInt32 OI { get; set; }
}

用法

var jtoken = JToken.Parse(input);

var data = jtoken["data"]["candles"]
    .Select(x => new Historical
    {
       TimeStamp = x[0].Value<DateTime>(),
       Open = x[1].Value<decimal>(),
       Low = x[2].Value<decimal>(),
       High = x[3].Value<decimal>(),
       Close = x[4].Value<decimal>()
       //...
    });

foreach (var item in data)
   Console.WriteLine($"{item.TimeStamp},Open {item.Open},Low {item.Low} ...");

输出

2/11/2020 4:30:00 AM, Open 1065, Low 1079.95 ...
3/11/2020 4:30:00 AM, Open 1072, Low 1079.4 ...

注意:还有很多方法可以处理数据时间以及如何配置 Json.net 或TryParse为您提供所需的结果。这是一个例子,由你决定,只关注投影。


如果您需要在构造函数中完成此操作

public struct Historical
{
   public Historical(JToken x)
   {
      TimeStamp = x[0].Value<DateTime>();
      Open = x[1].Value<decimal>();
      Low = x[2].Value<decimal>();
      High = x[3].Value<decimal>();
      Close = x[4].Value<decimal>();
      ...
   }
   public DateTime TimeStamp { get; }
   public decimal Open { get; }
   public decimal High { get; }
   public decimal Low { get; }
   public decimal Close { get; }
   ...     
}

...

var data = jtoken["data"]["candles"].Select(x => new Historical(x));

推荐阅读