C#:使用x属性

时间:2018-01-24 18:54:10

标签: c# arrays json api parsing

我得到了一些Rest API的响应,它只返回一些数组,如下所示:

[
[123,"0.01","0.02","0.03","0.04","12345.00000",123456789,"300.000",4000,"123.000","456.000","0"],
[456,"0.04","0.03","0.02","0.01","54321.00000",987654321,"500.000",4000,"123.000","456.000","1"],
[789,"0.05","0.06","0.07","0.08","12345.00000",123456789,"700.000",8000,"456.000","123.000","0"]    
]

在此示例中,数据集的数量为3,但数量总是不同的,也可能是100+。

我希望将其读入一个类对象,该对象根据响应中显示的每种类型的值有12个数组:

public class foo
{
    ...
    public int[] firstParam;
    public string[] secondParam;
    public string[] thirdParam;

    ...        
}

例如,firstParam应包含{123,456,789}; secondParam应包含{"0.01","0.04","0.05"}等等。

列的架构已知并记录在Public Rest API for Binance: Kline/Candlestick data.中。一个例子是https://api.binance.com/api/v1/klines?symbol=XVGBTC&interval=1h

之类的查询

2 个答案:

答案 0 :(得分:1)

API响应完全有效JSON;它是一个锯齿状的2d原始值数组,其中列具有Public Rest API for Binance: Kline/Candlestick data中定义的特定含义。因此,可以使用对其进行解析和反序列化,例如作为object [][]

var arrays = JsonConvert.DeserializeObject<object [][]>(jsonString);

(示例工作.Net fiddle #1。)

但是,我不建议将JSON反序列化为锯齿状的2d对象数组,或者(如您在问题中所建议的)具有与列值对应的数组属性的单个根对象,我建议您设计一个类BinanceKlineData表示这些特定列的单行值,然后使用custom JsonConverter中的C# JSON.NET - Deserialize response that uses an unusual data structure List<BinanceKlineData>反序列化为ObjectToArrayConverter<BinanceKlineData>

首先,使用列中记录的含义,您可以按如下方式定义类型BinanceKlineData

public class BinanceKlineData
{
    [JsonProperty(Order = 1)]
    public long OpenTime { get; set; }
    [JsonProperty(Order = 2)]
    public decimal Open { get; set; } // Or string, if you prefer
    [JsonProperty(Order = 3)]
    public decimal High { get; set; } // Or string, if you prefer
    [JsonProperty(Order = 4)]
    public decimal Low { get; set; } // Or string, if you prefer
    [JsonProperty(Order = 5)]
    public decimal Close { get; set; } // Or string, if you prefer
    [JsonProperty(Order = 6)]
    public decimal Volume { get; set; } // Or string, if you prefer
    [JsonProperty(Order = 7)]
    public long CloseTime { get; set; }
    [JsonProperty(Order = 8)]
    public decimal QuoteAssetVolume { get; set; } // Or string, if you prefer
    [JsonProperty(Order = 9)]
    public long NumberOfTrades { get; set; } // Should this be an long or a decimal?
    [JsonProperty(Order = 10)]
    public decimal TakerBuyBaseAssetVolume { get; set; }
    [JsonProperty(Order = 11)]
    public decimal TakerBuyQuoteAssetVolume { get; set; }
    // public string Ignore { get; set; }
}

请注意,我已使用[JsonProperty(Order = N)]注释了属性。此顺序对应于Rest API中列的顺序,并将用于通知Json.NET如何按列索引将列映射到属性。另请注意,我将数字列建模为decimal,尽管它们在JSON中显示为字符串。如果您更喜欢更直接的反序列化,可以使用string

接下来,从this answer抓取通用ObjectToArrayConverter<T>。它具有使用Order = N元数据通过列索引将行值映射到泛型类型T中的成员值的逻辑。

最后,您将能够将JSON反序列化为List<BinanceKlineData>,如下所示:

var settings = new JsonSerializerSettings
{
    Converters = { new ObjectToArrayConverter<BinanceKlineData>() },
};

var root = JsonConvert.DeserializeObject<List<BinanceKlineData>>(jsonString, settings);

示例工作.Net fiddle #2

或者,如果您愿意,可以将转换器直接应用于BinanceKlineData,如下所示:

[JsonConverter(typeof(ObjectToArrayConverter<BinanceKlineData>))]
public class BinanceKlineData
{
    // Remainder as before
}

当转换器直接应用于该类型时,不再需要通过JsonSerializerSettings.Converters传递它。

示例fiddle #3

答案 1 :(得分:0)

根据确切的响应格式,您可以执行以下操作:

var s = "[[123,\"0.01\",\"0.02\",\"0.03\",\"0.04\",\"12345.00000\",123456789,\"300.000\",4000,\"123.000\",\"456.000\",\"0\"],[456,\"0.04\",\"0.03\",\"0.02\",\"0.01\",\"54321.00000\",987654321,\"500.000\",4000,\"123.000\",\"456.000\",\"1\"],[789,\"0.05\",\"0.06\",\"0.07\",\"0.08\",\"12345.00000\",123456789,\"700.000\",8000,\"456.000\",\"123.000\",\"0\"]]";

var lines = s.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries).Select(a => a.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(b => b.TrimEnd('"').TrimStart('"')).ToArray()).Where(a => a.Any());

var c = lines.Count();

var foo = new foo
{
    firstParam = new int[c],
    secondParam = new string[c],
    thirdParam = new string[c]
};

for (int i = 0; i < c; i++)
{
    foo.firstParam[i] = Int32.Parse(lines.ElementAt(i)[0]);
    foo.secondParam[i] = lines.ElementAt(i)[1];
    foo.thirdParam[i] = lines.ElementAt(i)[2];
}

Console.WriteLine(string.Join(", ", foo.firstParam)); \\123, 456, 789
Console.WriteLine(string.Join(", ", foo.secondParam)); \\0.01, 0.04, 0.05
Console.WriteLine(string.Join(", ", foo.thirdParam)); \\0.02, 0.03, 0.06