【问题标题】:How to deserialize JSON to complex object in C#如何在 C# 中将 JSON 反序列化为复杂对象
【发布时间】:2017-07-03 08:31:05
【问题描述】:

我正在尝试将 json 结果反序列化为想要的对象。我得到的结果是:

{
    "base": "EUR",
    "date": "2017-06-30",
    "rates": {
        "AUD": 1.4851,
        "BGN": 1.9558,
        "BRL": 3.76,
        "CAD": 1.4785
    }
}

我希望这个结果反序列化为我的对象:

public class ExchangeRates
{
    public string Base { get; set; }

    public DateTime Date { get; set; }

    public IList<Rates> Rates { get; set; }
}

public class Rates
{
    public string Name { get; set; }

    public decimal Value { get; set; }
}

我的反序列化如下所示:

 using (var httpClient = new HttpClient())
 {
     var response = httpClient.GetAsync("http://api.fixer.io/latest").Result;
     var result = response.Content.ReadAsStringAsync().Result;
     var values = JsonConvert.DeserializeObject<ExchangeRates>(result);
 }

当我运行程序时,出现以下异常:

Newtonsoft.Json.JsonSerializationException: '无法将当前 JSON 对象(例如 {"name":"value"}) 反序列化为类型 'System.Collections.Generic.List`1[ConsoleApp4.Rates]' 因为该类型需要正确反序列化的 JSON 数组(例如 [1,2,3])。 要修复此错误,要么将 JSON 更改为 JSON 数组(例如 [1,2,3]),要么将反序列化类型更改为普通的 .NET 类型(例如,不是像整数这样的原始类型,而不是像这样的集合类型可以从 JSON 对象反序列化的数组或列表。 JsonObjectAttribute 也可以添加到类型中以强制它从 JSON 对象反序列化。 路径“rates.AUD”,第 1 行,位置 49。

如何将 JSON 反序列化为我想要的对象??

更新 1

或者我可以反序列化“rates”列表?

【问题讨论】:

  • 基本上,你没有List&lt;Rates&gt; - 你有一个Dictionary&lt;string, decimal&gt;
  • @JonSkeet 是的,我看到使用 Dictionary 工作正常,但是在反序列化后我需要将该字典映射到列表,因为我需要将所有这些汇率放入 DB,所以我想也许我可以将 JSON 反序列化为我想要的对象,所以我不需要映射
  • 它们在字典中并不会阻止您将它们放入 Db 中
  • 假设您不关心订单,您可以轻松创建一个列表:rateDictionary.Select(kvp =&gt; new Rates { Name = kvp.Key, Value = kvp.Value }).ToList()
  • 你能改变Json吗?如果没有,字典就是要走的路

标签: c# json serialization


【解决方案1】:

看看你的 JSON,特别是 rates

"rates": {
    "AUD": 1.4851,
    "BGN": 1.9558,
    "BRL": 3.76,
    "CAD": 1.4785
}

这很明显是一个 JSON 对象,因为它有键值对。但是,查看您的代码,您已将相应的属性 (Rates) 定义为 IList

public IList<Rates> Rates { get; set; }

我理解您定义Rates 类的原因。您认为通过定义该类,NewtonSoft 将按照您希望的方式反序列化 rates。但是,这是不可能的,因为rates 不是数组,因此将其反序列化为任何类型的IList 都是不可能的。

最简单、最明确的解决方案是使用字典:

public Dictionary<string, decimal> Rates { get; set; }

但是,如果您不想使用字典,则需要像这样修改 JSON,您的解决方案将起作用:

"rates":[  
  {  
     "Name":"AUD",
     "Value":1.4851
  },
  {  
     "Name":"BGN",
     "Value":1.9558
  },
  {  
     "Name":"BRL",
     "Value":3.76
  },
  {  
     "Name":"CAD",
     "Value":1.4785
  }
]

通过将rates 转换为数组,并使其内容对象而不是键值对,NewtonSoft 可以将rates 反序列化为列表,并将其内容反序列化为Rates 类的实例。

【讨论】:

  • 第二段 JSON 无效 - 您需要每个元素都是一个对象。
  • 摆弄 json 文档需要更多的工作并且容易出错。
  • @SirRufo 是的,但 OP 提到他们不想使用字典。
  • OP 在费率对象中指定小数,这对货币有意义,此回复中建议的字典是浮动的。只是说:)
【解决方案2】:

我同意其他人的观点:你应该使用字典。要实现到最终对象结构的转换,您可以使用例如带有显式转换运算符的中间类。

using System;
using Newtonsoft.Json;
using System.Collections.Generic;

public class Program
{
    public void Main()
    {
        var result = @"{
        ""base"": ""EUR"",
        ""date"": ""2017-06-30"",
        ""rates"": {
            ""AUD"": 1.4851,
            ""BGN"": 1.9558,
            ""BRL"": 3.76,
            ""CAD"": 1.4785
        }}";

        var values = (ExchangeRates) JsonConvert.DeserializeObject<TempExchangeRates>(result);


        Console.WriteLine(values.Base);
        Console.WriteLine(values.Date);

        foreach(var rate in values.Rates)
            Console.WriteLine(rate.Name + ": " + rate.
    }
}

public class TempExchangeRates
{
    public string Base { get; set; }
    public DateTime Date { get; set; }
    public Dictionary<string,decimal> Rates { get; set; }
    public static explicit operator ExchangeRates(TempExchangeRates tmpRates)
    {
        var xRate = new ExchangeRates();

        xRate.Base = tmpRates.Base;
        xRate.Date = tmpRates.Date;
        xRate.Rates = new List<Rates>();

        foreach(var de in tmpRates.Rates)
            xRate.Rates.Add(new Rates{Name = de.Key, Value = de.Value});

        return xRate;
    }
}


public class ExchangeRates
{
    public string Base { get; set; }
    public DateTime Date { get; set; }
    public IList<Rates> Rates { get; set; }
}

public class Rates
{
    public string Name { get; set; }
    public decimal Value { get; set; }
}

【讨论】:

  • Main() 结束未完成:Console.WriteLine(rate.Name + ": " + rate.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-23
相关资源
最近更新 更多