第三方 JSON API 中的两个不同值,使 Newtonsoft 中断

two different values in third party JSON API, making Newtonsoft break

嗨,我希望你能帮上忙。

我正在将来自第三方 API 的 Stocks 数据转换为 c# 数据类型,但问题是,JSON 对象有多个值。

例如:

"sharesShortPriorMonth":{"raw":4680878,"fmt":"4.68M","longFmt":"4,680,878"}

我想要的是 fmt 值 (4.68M),我正在尝试将其放入 C# 字段 public string sharesShortPriorMonth { get; set; }

我的问题是,当我从 JSON 字符串反序列化时,它期待更像 "sharesShortPriorMonth": "4.68M"

的东西

如何告诉 Json.NET 取那个值?

我已经检查了文档,JSON属性 属性不是我想要的,因为它映射了不同的名称。不是子值。

提前致谢。

您需要将 sharesShortPriorMonth 更改为代表现有 json 结构的类型(您可以只包含需要的属性):

public SharesShortPriorMonth sharesShortPriorMonth { get; set; }

public class SharesShortPriorMonth
{
    public string fmt { get; set; }
}

或创建custom converter and mark field with corresponding attribute.

我会用这样的东西

public class Stocks
{
    ... another properties

    [JsonProperty("sharesShortPriorMonth")]
    public JObject sharesShortPriorMonthJo { set { sharesShortPriorMonth = (string) value["fmt"]; }}
    [JsonIgnore] 
    public string sharesShortPriorMonth { get; private set;}
}

就我个人而言,我会选择@Serge 的解决方案(但我认为 sharesShortPriorMonthJo 属性 应该是 private 因为从外面看没有必要,但对于客户)。如果你想让你的 class 尽可能干净,那么你可以使用自定义的 JsonConverter,正如 @GuruStron 所指出的。但是,复杂度刚好移到另一个class,正好是JsonConverter


您可以使用的最简单的 (?) JsonConverter 是:

public class CustomConverter : JsonConverter<string>
{
    public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    
    public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var tokens = new Dictionary<string, object>();
        serializer.Populate(reader, tokens);
        
        return (string) tokens["fmt"] ?? throw new JsonReaderException(@"""fmt"" not found in sharesShortPriorMonth");
    }
}

Populate 方法在这种情况下非常方便,因为我们可以填写一个包含所有 json 属性的字典,最终我们只需要检索 fmt 属性.

Stocksclass变为:

public class Stocks
{
    [JsonConverter(typeof(CustomConverter))]
    public string sharesShortPriorMonth { get; set; }
}