Доступ к уже десериализованным свойствам из JsonConverter.ReadJson - PullRequest
1 голос
/ 31 января 2020

Я пытаюсь решить проблему обратной совместимости при десериализации старого json. Раньше существовало свойство double, и теперь оно изменено на пользовательский тип.

Моя идея - прочитать double и просто преобразовать его с помощью пользовательского конвертера json.

До этого было:

public class A
{
    [JsonProperty)]
    string Name { get; set; }
    [JsonProperty)]
    double Value { get; set; }
}

Сериализуется как

{"Name":"test","Value":33.0}

Новый:

public class A
{
    [JsonProperty]
    [JsonConverter(typeof(MyJsonConverter))]
    public MyType Value { get; set; }
}

Сериализуется как

{"Value":{"Value":33.0,"Name":"test", ...}},

Преобразователь:

public class MyJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => true;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value is double value)
            return new MyType(value, ???); // here is the problem, I need Name value here
        return reader.Value;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
        JToken.FromObject(value).WriteTo(writer);
}

но для построения MyType мне нужен строковый параметр, который является значением другого свойства Name

Как получить значение Name из конвертера для Value? Как получить доступ ко всему, что было десериализовано? Есть ли какое-то дерево? Дерево токенов?

Другое дело: в методе WriteJson я хочу делать «ничего» особенного, правильна ли моя реализация? Или есть простой способ не допустить, чтобы преобразователь делал что-то «особенное» при сериализации?

1 Ответ

1 голос
/ 31 января 2020

Вам необходимо применить конвертер к вашему родительскому классу A:

[JsonConverter(typeof(MyJsonConverter))]
public class A
{
    public MyType Value { get; set; }
}

public class AConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => objectType == typeof(A);

    public override bool CanWrite => false;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jObject = JObject.Load(reader);

        // Check if the keys contains "Name"
        string name = jObject["Name"]?.ToString();

        var a = new A();

        if (name != null)
        {
            a.Value = new MyType
            {
                Name = name,
                Value = jObject["Value"].Value<double>()
            };
        }
        else
        {
            a.Value = jObject["Value"].ToObject<MyType>();
        }

        return a;
    }

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

Чтобы использовать serailisation по умолчанию, просто переопределите CanWrite с помощью false.

...