Десериализовать вложенный элемент путем объединения UnixDateTimeConverter и ContractResolver - PullRequest
1 голос
/ 04 апреля 2020

Учитывая следующее 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);
    }
}

Как бы я go объединил вышеприведенный код, чтобы я мог десериализовать Response, используя конструктор и преобразование метки времени.

Я видел JsonConverter, JsonConstructor, CustomContractResolver и [JsonConverter(typeof(UnixDateTimeConverter))], чтобы отсортировать преобразование времени, но я не понимаю, как объединить все эти классы.

1 Ответ

0 голосов
/ 05 апреля 2020

Я получил эту работу, используя 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...