将 JSON 反序列化为 C# 类

Posted

技术标签:

【中文标题】将 JSON 反序列化为 C# 类【英文标题】:Deserializing JSON to C# Class 【发布时间】:2021-06-02 21:05:10 【问题描述】:

我正在调用一个返回 JSON 数据的 API,如下所示(该数组大约有 500 个项目):

[
    [
        1571702400000,
        "8197.28000000",
        "8297.99000000",
        "8000.00000000",
        "8020.00000000",
        "34651.82866300",
        1571788799999,
        "283535483.41051363",
        384699,
        "16767.03682400",
        "137253195.95826291",
        "0"
    ],
    [
        1614816000000,
        "50349.37000000",
        "51773.88000000",
        "49010.10000000",
        "49653.85000000",
        "25551.11905400",
        1614902399999,
        "1280981565.05072601",
        731056,
        "12197.45497900",
        "611820740.21554123",
        "0"
    ]
]

我正在尝试使用 JsonConvert.DeserializeObject(result) 解析这些数据。

我尝试过的两次尝试(见下文)都会产生以下错误:

错误信息

无法将当前 JSON 数组(例如 [1,2,3])反序列化为类型 '...+CandleSticks',因为该类型需要 JSON 对象(例如 "name":"value")才能正确反序列化.

要修复此错误,请将 JSON 更改为 JSON 对象(例如 "name":"value")或将反序列化类型更改为数组或实现集合接口的类型(例如 ICollection、IList),例如可以从 JSON 数组反序列化的列表。 JsonArrayAttribute 也可以添加到类型中以强制它从 JSON 数组反序列化。 路径'',第 1 行,位置 1。

尝试 #1:

public class CandleStick

    public List<List<object>> MyArray  get; set;  

...
CandleStick myCandles = JsonConvert.DeserializeObject<CandleStick>(result);

尝试 #2:

public class CandleStick

    public long openTime  get; set; 
    public string open  get; set; 
    public string high  get; set; 
    public string low  get; set; 
    public string close  get; set; 
    public string volume  get; set; 
    public long closeTime  get; set; 
    public string quoteAssetVolume  get; set; 
    public int numberOfTrades  get; set; 
    public string takerBuyBaseAssetVolume  get; set; 
    public string takerBuyQuoteAssetVolume  get; set; 
    public string ignore  get; set; 

...
List<CandleStick> myCandles = (List<CandleStick>)JsonConvert.DeserializeObject(result, typeof(List<CandleStick>));

我应该如何将 JSON 数据正确解析为 C# 类?

编辑 - 更新

我现在可以反序列化“无用”的 JSON,如下所示:

var arrays = JsonConvert.DeserializeObject<List<List<object>>>(result);
            IEnumerable<CandleStick> candles = from values in arrays
                               select new CandleStick
                               
                                   openTime = Convert.ToInt64(values[0]),
                                   open = Convert.ToString(values[1]),
                                   high = Convert.ToString(values[2]),
                                   low = Convert.ToString(values[3]),
                                   close = Convert.ToString(values[4]),
                                   volume = Convert.ToString(values[5]),
                                   closeTime = Convert.ToInt64(values[6]),
                                   quoteAssetVolume = Convert.ToString(values[7]),
                                   numberOfTrades = Convert.ToInt32(values[8]),
                                   takerBuyBaseAssetVolume = Convert.ToString(values[9]),
                                   takerBuyQuoteAssetVolume = Convert.ToString(values[10]),
                                   ignore = Convert.ToString(values[11])
                               ;

CandleStick cd = candles.ElementAt(0);

当我尝试引用蜡烛的元素时,我收到一条错误消息,指出预期的字符串格式不正确。

我傻了!如果我更仔细地考虑它,错误消息是有道理的。我的数组没有正确转换其中一个元素。现在我可以按预期引用数据 - ElementAt(x) .ToList() 等。

【问题讨论】:

如果您在 JSON 中有一个对象 (...),那么您需要一个 C# 中的类。如果您有 JSON 中的数组 ([...]),则需要 C# 中的集合类型。您在尝试 1 中拥有的是一个包含对象数组的对象。这与您的 JSON 不匹配,后者是对象数组的数组。使用尝试 2,您有一个对象数组,这又与您的 JSON 不匹配。我希望JsonConvert.DeserializeObject&lt;List&lt;List&lt;object&gt;&gt;&gt; 不幸的是,按照 JSON 的设计方式,您最好的选择是将其反序列化为 List&lt;List&lt;object&gt;&gt;。 JSON 中没有属性,只有对象数组,我假设它们对应于您的类上的属性,但您必须自己进行映射。 您的 JSON 虽然有效,但不是非常有用的格式。通常 json 包含字段名称和值,你只有一个值列表,所以它无法与 #2 一起使用。 【参考方案1】:

您的第 1 次尝试即将完成。

你可以这样做:

var arrays = JsonConvert.DeserializeObject<List<List<object>>>(json);

但是您必须自己进行映射:

var candlesticks =
    from values in arrays
    select new CandleSticks
    
        openTime = Convert.ToInt64(values[0]),
        open = Convert.ToString(values[1]),
        high = Convert.ToString(values[2]),
        ...
    ;

我知道大多数值已经采用正确的格式,所以至少对于字符串,您可能可以通过大小写来处理,例如 high = (string)values[2],但对于您真正想要使用的 long 和 ints @987654325 @,因为小的整数值可能会变成整数,而更大的值可能会变成长整数,所以你不能简单地转换。

【讨论】:

感谢发帖 - 非常有帮助。如何访问烛台?我尝试了以下方法,但收到有关字符串格式不正确的错误。 List 蜡烛 = candlesticks.ToList(); 那么您尝试转换的字符串之一不是您认为的那样,就像您想要一个 long 或一个 int,而是 json 包含一个字符串。 再次感谢 Lasse。我明白你的意思。晚上又工作太晚了,我的大脑变成了污泥:) 恕我直言,序列化为List&lt;List&lt;JToken&gt;&gt;,然后您只需使用显式转换运算符newtonsoft.com/json/help/html/…。

以上是关于将 JSON 反序列化为 C# 类的主要内容,如果未能解决你的问题,请参考以下文章

Boost 将派生类反序列化为基类指针

Jackson - 使用泛型类反序列化

将 JSON 字符串反序列化为多个 C# 对象

将 JSON 反序列化为 C# 类

无法将 JSON 数组反序列化为 C# 对象 [关闭]

无法将 JSON 字符串反序列化为 C# 对象