#c# #arrays #json #facebook-c#-sdk
#c# #массивы #json #facebook-c #-sdk
Вопрос:
У меня есть следующий объект, получающий возврат от одного из 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; }
}
Есть ли правильный / элегантный способ заставить его работать. Также, что я здесь чего-то не хватает?
Комментарии:
1. Пробовал это, но получаю сообщение об ошибке « Не удается десериализовать текущий JSON …«
2. Да, я не заметил, что какой-то веб-разработчик решил разбить кучу типизированных данных на список и назвать его candle .
Ответ №1:
- Основная проблема заключается в том, что это недопустимый json. Однако давайте исправим это и предположим, что это правильно. Если это то, что вы получаете от некоторых ресурсов, я предлагаю вам связаться с ними и пожаловаться.
- Существует множество способов сделать это. Поскольку вы использовали 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));
Комментарии:
1. Спасибо за ответ. Но есть ли способ сделать это без обновления свойства set исторического класса? Определение, которое я только что получил.