Deserializing polymorphic json classes without type information using json.net

后端 未结 5 1066
暖寄归人
暖寄归人 2020-11-21 06:10

This Imgur api call returns a list containing both Gallery Image and Gallery Album classes represented in JSON.

I can\'t see how to

5条回答
  •  逝去的感伤
    2020-11-21 06:31

    You can do this fairly easily by creating a custom JsonConverter to handle the object instantiation. Assuming you have your classes defined something like this:

    public abstract class GalleryItem
    {
        public string id { get; set; }
        public string title { get; set; }
        public string link { get; set; }
        public bool is_album { get; set; }
    }
    
    public class GalleryImage : GalleryItem
    {
        // ...
    }
    
    public class GalleryAlbum : GalleryItem
    {
        public int images_count { get; set; }
        public List images { get; set; }
    }
    

    You would create the converter like this:

    public class GalleryItemConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(GalleryItem).IsAssignableFrom(objectType);
        }
    
        public override object ReadJson(JsonReader reader, 
            Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jo = JObject.Load(reader);
    
            // Using a nullable bool here in case "is_album" is not present on an item
            bool? isAlbum = (bool?)jo["is_album"];
    
            GalleryItem item;
            if (isAlbum.GetValueOrDefault())
            {
                item = new GalleryAlbum();
            }
            else
            {
                item = new GalleryImage();
            }
    
            serializer.Populate(jo.CreateReader(), item);
    
            return item;
        }
    
        public override bool CanWrite
        {
            get { return false; }
        }
    
        public override void WriteJson(JsonWriter writer, 
            object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    Here's an example program showing the converter in action:

    class Program
    {
        static void Main(string[] args)
        {
            string json = @"
            [
                {
                    ""id"": ""OUHDm"",
                    ""title"": ""My most recent drawing. Spent over 100 hours."",
                    ""link"": ""http://i.imgur.com/OUHDm.jpg"",
                    ""is_album"": false
                },
                {
                    ""id"": ""lDRB2"",
                    ""title"": ""Imgur Office"",
                    ""link"": ""http://alanbox.imgur.com/a/lDRB2"",
                    ""is_album"": true,
                    ""images_count"": 3,
                    ""images"": [
                        {
                            ""id"": ""24nLu"",
                            ""link"": ""http://i.imgur.com/24nLu.jpg""
                        },
                        {
                            ""id"": ""Ziz25"",
                            ""link"": ""http://i.imgur.com/Ziz25.jpg""
                        },
                        {
                            ""id"": ""9tzW6"",
                            ""link"": ""http://i.imgur.com/9tzW6.jpg""
                        }
                    ]
                }
            ]";
    
            List items = 
                JsonConvert.DeserializeObject>(json, 
                    new GalleryItemConverter());
    
            foreach (GalleryItem item in items)
            {
                Console.WriteLine("id: " + item.id);
                Console.WriteLine("title: " + item.title);
                Console.WriteLine("link: " + item.link);
                if (item.is_album)
                {
                    GalleryAlbum album = (GalleryAlbum)item;
                    Console.WriteLine("album images (" + album.images_count + "):");
                    foreach (GalleryImage image in album.images)
                    {
                        Console.WriteLine("    id: " + image.id);
                        Console.WriteLine("    link: " + image.link);
                    }
                }
                Console.WriteLine();
            }
        }
    }
    

    And here is the output of the above program:

    id: OUHDm
    title: My most recent drawing. Spent over 100 hours.
    link: http://i.imgur.com/OUHDm.jpg
    
    id: lDRB2
    title: Imgur Office
    link: http://alanbox.imgur.com/a/lDRB2
    album images (3):
        id: 24nLu
        link: http://i.imgur.com/24nLu.jpg
        id: Ziz25
        link: http://i.imgur.com/Ziz25.jpg
        id: 9tzW6
        link: http://i.imgur.com/9tzW6.jpg
    

    Fiddle: https://dotnetfiddle.net/1kplME

提交回复
热议问题