@KislyFan
инженер, связист и просто любитель выпить

Custom JsonConverter когда тип для десериализации определяется одним из ключей?

Приветствую!

У меня есть json с интересной структурой, где содержимое определяется полем Type.

public class Response : List<ResponseBase>
    {
    }

    public class ResponseBase
    {
        public string Type { get; set; }
    }

    // type = line
    public class ResponseLine : ResponseBase
    {
        public string Value { get; set; }
    }

    // type = bigline
    public class ResponseLineBig : ResponseBase
    {
        public string Title { get; set; }
    }

    // type = summary
    public class ResponseSummary : ResponseBase
    {
        public int ErrorCode { get; set; }
        public string ErrorMessage { get; set; }
        public string LogReference { get; set; }
        public string StatusMessage { get; set; }
        public string SuggestedSolution { get; set; }
    }


Я сейчас сделал JsonConverter, но чтение и назначение свойств делается руками. Если я не хочу проделывать это руками (много разных типов в json), есть ли возможность сделать это проще ?
//использую так
    //var response = await JsonSerializer.DeserializeAsync<Response>(responseStream, SerializerOptions);

    public class ReadOnlyJsonConverter : JsonConverter<ResponseBase>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return typeof(ResponseBase) == typeToConvert;
        }

        public override void Write(Utf8JsonWriter writer, ResponseBase value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }

        public override ResponseBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            using (JsonDocument document = JsonDocument.ParseValue(ref reader))
            {
                string dtoType = document.RootElement.Clone().GetProperty("Type").GetString();

                switch (dtoType)
                {
                    case "command":
                    case "line":
                        return ReadLine(document.RootElement.Clone());

                    case "summary":
                        return ReadSummary(document.RootElement.Clone());

                    default:
                        return null;
                }
            }
        }

        private ResponseLine ReadLine(JsonElement document)
        {
            var response = new ResponseLine()
            {
                Type = "line"
            };

            if (document.TryGetProperty("value", out JsonElement jsonElement))
            {
                response.Value = jsonElement.GetString();
            }

            return response;
        }

        private ResponseSummary ReadSummary(JsonElement document)
        {
            var response = new ResponseSummary()
            {
                Type = "summary"
            };

            if (document.TryGetProperty("errorMessage", out JsonElement jsonElementErrorMessage))
            {
                response.ErrorMessage = jsonElementErrorMessage.GetString();
            }

            if (document.TryGetProperty("statusMessage", out JsonElement jsonElementStatusMessage))
            {
                response.StatusMessage = jsonElementStatusMessage.GetString();
            }

            return response;
        }
    }
  • Вопрос задан
  • 109 просмотров
Пригласить эксперта
Ответы на вопрос 1
@AndromedaStar
.Net - monkey
Нет, проще сделать нельзя, но переработать код, чтобы он стал более гибким и красивым - это нужно обязательно.
Я бы сделал фабрику конвертеров, и в зависимости от типа бы создавался бы нужный конвертер.
В любом случае для каждого нового типа стратегию придется описывать, от этого никуда не денешься. Просто выбор стратегии точно не должен быть в методе Read.
Еще есть такая штука для полиморфной обработки, я вот вспомнил:
https://www.newtonsoft.com/json/help/html/Serializ...
Может это тоже поможет, просто не совсем полностью задача сформулирована.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы