首页 > 解决方案 > 通过结合 UnixDateTimeConverter 和 ContractResolver 反序列化嵌套项

问题描述

鉴于以下 JSON,我想用 Newtonsoft.Json 反序列化:

{
  "ticker": "AAPL",
  "status": "OK",
  "adjusted": true,
  "queryCount": 55,
  "resultsCount": 2,
  "results": [
    {
      "T": "AAPL",
      "v": 31315282,
      "o": 102.87,
      "c": 103.74,
      "h": 103.82,
      "l": 102.65,
      "t": 1549314000000,
      "n": 4
    },
    {
      "T": "AAPL",
      "v": 11315282,
      "o": 102.13,
      "c": 103.44,
      "h": 104.12,
      "l": 102.33,
      "t": 1549315000000,
      "n": 4
    }
  ]
}

我已经创建了可以反序列化的类:

public class Response
{
    public string Ticker { get; set; }
    public string Status { get; set; }
    public bool Adjusted { get; set; }
    public int QueryCount { get; set; }     
    public int ResultsCount { get; set; }
    [JsonProperty("results")]
    public List<OpenHighLowClose> OpenHighLowCloseList { get; set; }
}

而且我有以下DTO,它在我的代码中使用(但我不想在这个类上放置属性):

public class OpenHighLowClose
{
    public OpenHighLowClose(DateTime dateTime, decimal open, decimal high, decimal low, decimal close, decimal volume)
    {
        DateTime = dateTime;
        Open = open;
        High = high;
        Low = low;
        Close = close;
        Volume = volume;
    }

    public DateTime DateTime { get; private set; }
    public Decimal Open { get; private set; }
    public Decimal High { get; private set; }
    public Decimal Low { get; private set; }
    public Decimal Close { get; private set; }
    public Decimal Volume { get; private set; }
}

我需要通过构造函数进行映射(我相信解串器默认会这样做),所以对于 OpenHighLowClose 我可以写如下:

public class OpenHighLowCloseContractResolver : DefaultContractResolver
{
    private Dictionary<string, string> PropertyMappings { get; set; }

    public CustomContractResolver()
    {
        this.PropertyMappings = new Dictionary<string, string> 
        {
            {"t", "DateTime"},
            {"o", "Open"},
            {"h", "High"},
            {"l", "Low"},
            {"c", "Close"},
            {"v", "Volume"},
        };
    }

    protected override string ResolvePropertyName(string propertyName)
    {
        string resolvedName = null;
        var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
        return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
    }
}

我将如何组合上面的代码,以便我可以Response使用构造函数和时间戳转换进行反序列化。

我已经看到JsonConverter,JsonConstructor和对时间转换CustomContractResolver进行[JsonConverter(typeof(UnixDateTimeConverter))]排序,但我对如何组合所有这些类感到困惑。

标签: c#jsonjson.net

解决方案


我使用JsonConverter.

这最终并没有那么糟糕,如果最佳实践与否,请对评论感兴趣:

public class AggregateResponse
{
    public string Ticker { get; set; }
    public string Status { get; set; }
    public bool Adjusted { get; set; }
    public int QueryCount { get; set; }
    public int ResultsCount { get; set; }
    public List<OpenHighLowClose> Results { get; set; }
}

public class OpenHighLowCloseConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);

        var timestamp = DateTimeOffset
                            .FromUnixTimeMilliseconds((long)obj["t"])
                            .UtcDateTime;

        return new OpenHighLowClose(
                            timestamp,
                            (decimal)obj["o"],
                            (decimal)obj["h"],
                            (decimal)obj["l"],
                            (decimal)obj["c"],
                            (int)obj["v"]);                            
    }

    public override bool CanConvert(Type objectType)
                                  => objectType == typeof(OpenHighLowClose);

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
                                  => throw new NotImplementedException();
}

我用以下反序列化:

var settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new OpenHighLowCloseConverter() }
};

var deserialized = JsonConvert.DeserializeObject<AggregateResponse>(result, settings);

推荐阅读