使用 json.net 反序列化没有类型信息的多态 json 类 [英] Deserializing polymorphic json classes without type information using json.net

查看:20
本文介绍了使用 json.net 反序列化没有类型信息的多态 json 类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个 Imgur api 调用返回一个包含两个画廊图像的列表和以 JSON 表示的画廊相册类.

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

我看不出如何使用 Json.NET 自动反序列化这些,因为没有 $type 属性告诉反序列化器要表示哪个类.有一个名为IsAlbum"的属性可用于区分两者.

I can't see how to deserialize these automatically using Json.NET given that there is no $type property telling the deserializer which class is meant to be represented. There is a property called "IsAlbum" that can be used to differentiate between the two.

这个问题似乎表明一种方法,但看起来有点像黑客.

This question appears to show one method but it looks like a bit of a hack.

我该如何反序列化这些类?(使用 C#、Json.NET).

样本数据:

图库图片

{
    "id": "OUHDm",
    "title": "My most recent drawing. Spent over 100 hours.",
        ...
    "is_album": false
}

相册

{
    "id": "lDRB2",
    "title": "Imgur Office",
    ...
    "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"
        }
    ]
}
}

推荐答案

通过创建自定义 JsonConverter 来处理对象实例化,您可以相当轻松地做到这一点.假设您的类定义如下:

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<GalleryImage> 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<GalleryItem> items = 
            JsonConvert.DeserializeObject<List<GalleryItem>>(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();
        }
    }
}

这是上面程序的输出:

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

小提琴:https://dotnetfiddle.net/1kplME

这篇关于使用 json.net 反序列化没有类型信息的多态 json 类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆