Десериализация json во вложенный класс

Всем привет. Есть, примерно, следующий json файл:

[{
        "a": "AA",
        "aa": "aaAA",
        "d": "DD",
        "dd": "ddDD",
        "c": "CC",
        "q": "QQ",
},
{
        "a": "AA",
        "aa": "aaAA",
        "d": "DD",
        "dd": "ddDD",
        "c": "CC",
        "q": "QQ",
}]

Полей в данном json значительно больше. Этот json нужно десериализовать в следующий класс:

public class Example
{
        [JsonIgnore]
        public A A { get; set; }

        [JsonIgnore]
        public D D { get; set; }

        [JsonProperty("c")]
        public string C { get; set; }

        [JsonProperty("q")]
        public string Q { get; set; }
}

где класс A:

public class A
{
        [JsonProperty("a")]
        public string a { get; set; }

        [JsonProperty("aa")]
        public string AA { get; set; }
}

Так же и с классом D. Первое что пришло в голову, раздельно десериализовать каждый класс и объеденить их все в классе Example. Сразу не понравилась идея, из-за будущих сложностей при расширении класса. Может есть лучший способ десериализации не вложенного json во вложенные классы?


Ответы (1 шт):

Автор решения: A K

Технически, если вы используете Json.Net то при парсинге json вы можете модифицировать как угодно получающуюся структуру подменяя нужные фрагменты JNode (я приводил примеры: раз, два, три, четыре...)

У вас придётся вешать кастомный конвертер прямо на класс и знать его внутреннюю структуру, как-то так:

public class NestedConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Type type = (Nullable.GetUnderlyingType(objectType) ?? objectType);
        bool isNullable = (Nullable.GetUnderlyingType(objectType) != null);

        var token = JToken.Load(reader);
        if (token == null || token.Type == JTokenType.Null)
        {
            if (!isNullable)
                throw new JsonSerializationException(string.Format("Null value for type {0} at path {1}", objectType.Name, reader.Path));
            return null;
        }
        if (token.Type == JTokenType.Object)
        {
            var nestedA = new NestedA();
            var nestedD = new NestedD();
            var q = "";
            foreach(JProperty abc in token.Children())
            {
                // TODO: Напрашивается рефлексия?
                
                if(abc.Name == nameof(NestedA.a))
                    nestedA.a = abc.Value.ToString();

                ...

                if (abc.Name == nameof(SomeClass.q))
                    q = abc.Value.ToString();
            }
            return new SomeClass
            {
                NestedA = nestedA,
                NestedD = nestedD,
                q = q,
            };
        }
        
        throw new Exception("Вот сейчас прям совсем неожиданно было");
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }
}

И такие классы:

[JsonConverter(typeof(NestedConverter))]
public class SomeClass
{
    public NestedA NestedA { get; set; }
    public NestedD NestedD { get; set; }
    public string q { get; set; }
}

public class NestedA
{
    public string a { get; set; }
    public string AA { get; set; }
}

public class NestedD
{
    public string d { get; set; }
    public string DD { get; set; }
}

Использование:

var source = @"[{
    ""a"": ""AA"",
    ""aa"": ""aaAA"",
    ""d"": ""DD"",
    ""dd"": ""ddDD"",
    ""c"": ""CC"",
    ""q"": ""QQ"",
    },
    {
            ""a"": ""AA"",
            ""aa"": ""aaAA"",
            ""d"": ""DD"",
            ""dd"": ""ddDD"",
            ""c"": ""CC"",
            ""q"": ""QQ"",
    }]";
var parsed = Newtonsoft.Json.JsonConvert.DeserializeObject<SomeClass[]>(source);
parsed.Dump();

Вуаля:

введите сюда описание изображения

Но я бы в вашем случае прислушался к рекомендациям сделать отдельно POCO-классы для сериализации и отдельно - модифицировать после в любой нужный вид. Это намного проще и нагляднее, чем потом читать колдовство разбора json.

→ Ссылка