Newtonsoft.JSON, десериализуйте разные поля JSON, похожие на один тип, но имеющие разное десериализованное поле объекта

#c# #json #json.net

#c# #json #json.net

Вопрос:

У меня есть JSON, в котором есть поля, которые более или менее выглядят следующим образом

 {
    "Photos" : 
    [
        {
            "file_id" : "Some value",
            "type" : "Some certain value",
            /*'Photo's specific fields*/
        },
        {
            "file_id" : "Some value",
            "type" : "Some certain value",
            /*'Photo's specific fields*/
        },
        {
            "file_id" : "Some value",
            "type" : "Some certain value",
            /*'Photo's specific fields*/
        }

    ],
    "Document" : 
    {
        "file_id" : "Some value",
        "type" : "Some certain value",
        /*'Document's specific fields*/
    },
    "Video" : 
    {
        "file_id" : "Some value",
        "type" : "Some certain value",
        /*'Video's specific fields*/
    },
}
  

Где весь JSON будет десериализован в этот класс

 public class APIResponse
{
    [JsonProperty(PropertyName = "Photos")]
    public List<APIFile> Photos;

    [JsonProperty(PropertyName = "Document")]
    public APIFile Document;

    [JsonProperty(PropertyName = "Video")]
    public APIFile Video;
}
  

Где APIFile — класс, который является «целевым типом» для десериализации каждого из этих полей JSON, это выглядит следующим образом

 public class APIFile
{
    public enum FileMIME
    {
        // Some already specified enum values
    }
    [JsonProperty(PropertyName = "file_id")]
    public string FileID;
    [JsonProperty(PropertyName = "type")]
    public string FileType;
    [JsonIgnore()]
    public FileMIME MIMEType;
}
  

Как вы можете видеть, эти три поля в JSON имеют некоторые общие поля, file_id и type , где Photos — коллекция определенного типа, которая также имеет одни и те же общие поля.

Проблема в том, как я могу десериализовать каждое из них, но установить MIMEType поле, соответствующее десериализованному полю? предпочтительно без использования JsonConverter или добавления дополнительного класса

Например, при десериализации поля JSON, Document тогда поле Document в APIResponse объекте будет создано с MIMEType полем, имеющим значение MIMEType.Document

Комментарии:

1. Почему бы не сделать APIFile быть абстрактным базовым классом и подклассировать его как APIPhoto , APIVideo , APIDocument и так далее?

2. Я пытаюсь уменьшить количество классов, которые я должен создать, чтобы выполнить это требование схемы JSON, и мне действительно не нужны остальные поля из каждого типа, это Telegram Bot API КСТАТИ, попробуйте посетить страницу API, посмотреть «Доступные типы», это огромный и очень -очень вложенный (по крайней мере, для меня)

Ответ №1:

Вы можете использовать установщики с резервными закрытыми полями:

     public enum FileMIME
    {
        Document,
        Photos,
        Video       
    }

    public class APIResponse
    {
        private List<APIFile> _photos;
        [JsonProperty(PropertyName = "Photos")]
        public List<APIFile> Photos
        {
            get { return _photos; }
            set {   _photos = value;
                    foreach(var photo in _photos)
                    {
                        photo.MIMEType = FileMIME.Photos;
                    }
                }
        }

        private APIFile _document;
        [JsonProperty(PropertyName = "Document")]
        public APIFile Document
        {
            get { return _document; }
            set { _document = value; _document.MIMEType = FileMIME.Document; }
        }

        private APIFile _video;
        [JsonProperty(PropertyName = "Video")]
        public APIFile Video
        {
            get { return _video; }
            set { _video = value; _video.MIMEType = FileMIME.Video; }
        }
    }
  

Комментарии:

1. Понятно, никогда не думал, set что их можно использовать подобным образом, но для этого требуется резервное значение. Тем не менее, несмотря на это, мне не пришлось создавать отдельный конвертер

2. однако еще один вопрос: могу ли я сделать что-то вроде value.MIME = MIMEType.Video then do _video = value или я могу сделать это только для резервного значения после value присвоения back-val ?

Ответ №2:

Вы могли бы использовать Dictionary<string, object> вместо класса APIFile. Затем вы можете добавить FileMIME в каждый словарь, прежде чем возвращать ответ.