【问题标题】:Get second level values from JSON string using C# and using a foreach使用 C# 并使用 foreach 从 JSON 字符串中获取二级值
【发布时间】:2018-11-01 08:00:47
【问题描述】:

完整的 JSON 新手 - 这是我第一次使用 C# 进入 JSON。

我有一条从 HTTP 获取请求返回的记录。

var exchRateData = Get($"https://api.exchangeratesapi.io/2018-10-30?base=EUR&symbols=AUD");

返回: {"date":"2018-10-30","rates":{"AUD":1.6025},"base":"EUR"}.

AUD 和 1.6025 值都是 GET 请求中的变量。因此 GET 请求可以针对它返回的 SGD 或 INR:

{"date":"2018-10-30","rates":{"SGD":0.0187977737},"base":"INR"}

总是返回一个带有级别的记录,就像上面的两个示例一样。

我想要的是访问二级值的值,

{"AUD":1.6025} or {"SGD":0.0187977737}

我试过了:

var jsonResult = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(exchRateData);
                    foreach (var keyValue in jsonResult)
                {
                    try
                    {
                        LblGetValues.Text = LblGetValues.Text + "Key: " + keyValue.Key + " Value:" + keyValue.Value + "<br>";
                        if (keyValue.Key == "date")
                            LblDate.Text = keyValue.Value;

//This is where I get stuck.
                        if (keyValue.Key == "rates")
                        {
// I would like to be able to do this here : 
//string currencyCode =  "AUD" (or "SGD" if second GET request)
//double currencyRate = 1.6025  (or 0.0187977737 if second GET request)
                            //JArray secondLevel = new JArray("rates");

                         //   LblRate.Text = keyValue.Value.ToString();

                        }

                        if (keyValue.Key == "base")
                            LblBase.Text = keyValue.Value;
                    }
                    catch (Exception errMsg)
                    {
                        LblMsg.Text = errMsg.Message + errMsg.StackTrace;
                    }
                }

请帮忙....

【问题讨论】:

  • 这可能会有所帮助 - 它有一个很好的扩展方法的答案:stackoverflow.com/questions/16079116/…
  • TheGeneral 有点被动攻击性。 ePossum,不过,作为记录,一个易于阅读的问题更容易回答,这里有一个指向标记的链接,用于格式化您将来可能遇到的问题:stackoverflow.com/editing-help
  • 我看不到你所说的“被动攻击”。今天早上我感觉很好,我不会让这个来自@user3577502 的小讽刺破坏我的一天。感谢 Mihir Dave 的解决方案。像魅力一样工作,你让我很开心....
  • @ePossum 如果您只请求一种货币而不是多种货币(例如api.exchangeratesapi.io/…),则可接受的解决方案将起作用。检查我的答案
  • 是的@Rui Jarimba。你说的对。但是,我确实接受了这个解决方案,因为我们在这个项目中只需要一个费率。我们需要在两个货币代码之间进行转换。 API 还具有多个日期、日期范围等选项,我们不希望通过查看返回单一汇率以外的解决方案来扩大范围,但是,您的回答很有用,因为我们将在完成转换后开始进行货币三角测量项目。这两个项目是完全独立的,因此无需为两者采用相同的解决方案。我当然已经标记了你的答案。

标签: c# arrays json.net


【解决方案1】:

我建议使用JSON.NET

在这里您将把您的 JSON 字符串反序列化到您的 c# 模型类中

您的模型类将如下所示Model Generated using json2csharp

public class Rates
{
    [JsonProperty(PropertyName = "fieldName")]
    public double currency { get; set; }
}

public class RootObject
{
    public string date { get; set; }
    public Rates rates { get; set; }
    public string @base { get; set; }
}

那么这就是你使用 JSON.NET 反序列化它的方式

// THis works for normal secanario but it won't work for you 
var exchangeRates = JsonConvert.DeserializeObject<RootObject>("Your Json String goes here");

但是你的 JSON 场景有点复杂,所以你必须使用 自定义合约解析器

这是一个例子

ContractResolver 类

internal class CustomContractResolver : DefaultContractResolver
{
    public CustomContractResolver(string fieldName)
    {
        FieldName = fieldName;
    }

    public string FieldName { get; set; }

    protected override string ResolvePropertyName(string propertyName)
    {
        return propertyName == "fieldName" ? FieldName : base.ResolvePropertyName(propertyName);
    }
}

如何使用此设置

var settings = new JsonSerializerSettings
{
    DefaultValueHandling = DefaultValueHandling.Ignore,
    MissingMemberHandling = MissingMemberHandling.Ignore,
    ContractResolver = new CustomContractResolver("Pass Your currency here")
};

// Make Http Calls here and replace returned string in below method

var data = JsonConvert.DeserializeObject<RootObject>("Your JSON String", setting);
// Here You can access your currency rates
double currencyRate = data.currency;

【讨论】:

  • 完美 - 我认为您的解决方案认识到将键作为变量的复杂性并很好地解决了该问题。我已经成功地实现了这一点,而不需要“foreach”循环。我必须做的唯一改变是用 base.rates.currency 替换 base.currency,这很简单。非常感谢,米希尔。
【解决方案2】:
   public class Rates
    {
        public double AUD { get; set; }
    }

    public class ObjectCurrency
    {
        public string date { get; set; }
        public Rates rates { get; set; }
        public string @base { get; set; }
    }


  var data= JsonConvert.DeserializeObject<ObjectCurrency>(exchRateData);

【讨论】:

  • 完美! “诀窍”是使用正确的“类型”调用JsonConvert.DeserializeObject&lt;T&gt;(),如您在此处所示。我不确定这段代码是否一定适用于 OP - 他可能需要更改一些内容。但这绝对是正确的做法。
  • 我在上面的笔记中已经指出:
  • 当请求从 AUD 变为 INR 时会发生什么?此代码将中断。
  • 我在上面的注释中已经指出:AUD 和 SGD 是 Get 请求中的变量。它可能是 MXP 甚至是其他一些变量。实际上,我有一个键,它是 JSON 语句中的一个变量。 AUD 可以是任何 3 位数的货币代码。 Rates 类可以包含 SGD、MXP 等?
  • 正确的@Mihir Dave 解决方案负责将 AUD 转换为 SGD 以及我们正在使用的 200 种世界货币中的任何其他货币。由于这个原因,上面的代码中断了..
【解决方案3】:

如果只有一个费率(这是 OP 想要的),则接受的解决方案可以正常工作,但它不适用于超过 1 个费率。此外,它增加了额外的复杂性,这可以通过使用 Dictionary 来避免(见下文)。

示例 - 以下请求(AUDUSDGBP

https://api.exchangeratesapi.io/2018-10-30?base=EUR&symbols=AUD,USD,GBP

将返回以下 json:

{"date":"2018-10-30","rates":{"USD":1.1372,"GBP":0.89148,"AUD":1.6025},"base":"EUR"}

您可以使用以下 C# 类来反序列化您的 json 字符串:

public class ExchangeRate
{
    [JsonProperty("date")]
    public string Date { get; set; }

    [JsonProperty("rates")]
    public Dictionary<string, decimal> Rate { get; set; }

    [JsonProperty("base")]
    public string Base { get; set; }
}

反序列化json字符串:

string json = @"{""date"":""2018-10-30"",""rates"":{""USD"":1.1372,""GBP"":0.89148,""AUD"":1.6025},""base"":""EUR""}";

ExchangeRate rate = JsonConvert.DeserializeObject<ExchangeRate>(json);

结果:

【讨论】:

  • 是的@Rui Jarimba。你说的对。但是,我确实接受了以前的解决方案,因为我们在这个项目中只需要一个费率。我们需要在两个货币代码之间进行转换。但是,您的回答很有用,因为我们将在完成转换项目后开始进行货币三角测量。这两个项目是完全独立的,因此无需为两者采用相同的解决方案。我当然已经标记了你的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-22
  • 2018-01-27
  • 2014-06-07
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多