当前位置: 首页 > 面试题库 >

使用Json.Net的多态JSON反序列化失败

颜文昌
2023-03-14
问题内容

我正在尝试使用自定义将一些JSON反序列化为各种子类 JsonConverter

我几乎遵循了这一点。

我的抽象基类:

abstract class MenuItem
{
    public String Title { get; set; }
    public String Contents { get; set; }
    public List<MenuItem> Submenus { get; set; }
    public String Source { get; set; }
    public String SourceType { get; set; }
    public abstract void DisplayContents();
}

而我的派生JsonConverter

class MenuItemConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(MenuItem).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject item = JObject.Load(reader);
            switch (item["SourceType"].Value<String>())
            {
                case SourceType.File:    return item.ToObject<Menu.FileMenu>();
                case SourceType.Folder:  return item.ToObject<Menu.FolderMenu>();
                case SourceType.Json:    return item.ToObject<Menu.JsonMenu>();
                case SourceType.RestGet: return item.ToObject<Menu.RestMenu>();
                case SourceType.Rss:     return item.ToObject<Menu.RssMenu>();
                case SourceType.Text:    return item.ToObject<Menu.TextMenu>();
                case SourceType.Url:     return item.ToObject<Menu.UrlMenu>();
                default: throw new ArgumentException("Invalid source type");
            }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }

SourceType 只是一个包含一些字符串常量的静态类。

JSON文件反序列化如下:

JsonConvert.DeserializeObject<MenuItem>(File.ReadAllText(menuPath), new MenuItemConverter());

现在,我的问题是,每当我运行代码时,都会出现以下错误:

An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code

Additional information: Could not create an instance of type ConsoleMenu.Model.MenuItem. Type is an interface or abstract class and cannot be instantiated. Path 'Submenus[0].Title', line 5, position 21.

有问题的Json文件如下所示:

{
    "Title": "Main Menu",
    "Submenus": [
        {
            "Title": "Submenu 1",
            "Contents": "This is an example of the first sub-menu",
            "SourceType": "Text"
        },
        {
            "Title": "Submenu 2",
            "Contents": "This is the second sub-menu",
            "SourceType": "Text"
        },
        {
            "Title": "GitHub System Status",
            "Contents": "{\"status\":\"ERROR\",\"body\":\"If you see this, the data failed to load\"}",
            "Source": "https://status.github.com/api/last-message.json",
            "SourceType": "RestGet"
        },
        {
            "Title": "TF2 Blog RSS",
            "Contents": "If you see this message, an error has occurred",
            "Source": "http://www.teamfortress.com/rss.xml",
            "SourceType": "Rss"
        },
        {
            "Title": "Submenus Test",
            "Contents": "Testing the submenu functionality",
            "Submenus": [
                {
                    "Title": "Submenu 1",
                    "Contents": "This is an example of the first sub-menu",
                    "SourceType": "Text"
                },
                {
                    "Title": "Submenu 2",
                    "Contents": "This is the second sub-menu",
                    "SourceType": "Text"
                }
            ]
        }
    ],
    "SourceType": "Text"
}

在我看来,反序列化嵌套对象有麻烦,我该如何解决?


问题答案:

首先,SourceType错过了您的json中的菜单项“ Submenus Test”。

其次,您不应该仅仅ToObject因为该Submenus属性而使用它,而应该以递归方式对其进行处理。

以下ReadJson将起作用:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var jObject = JObject.Load(reader);
    var sourceType = jObject["SourceType"].Value<string>();

    object target = null;

    switch (sourceType)
    {
        case SourceType.File: 
            target = new FileMenu(); break;
        case SourceType.Folder: 
            target = new FolderMenu(); break;
        case SourceType.Json: 
            target = new JsonMenu(); break;
        case SourceType.RestGet: 
            target = new RestMenu(); break;
        case SourceType.Rss: 
            target = new RssMenu(); break;
        case SourceType.Text: 
            target = new TextMenu(); break;
        case SourceType.Url: 
            target = new UrlMenu(); break;
        default: 
            throw new ArgumentException("Invalid source type");
    }

    serializer.Populate(jObject.CreateReader(), target);

    return target;
}


 类似资料:
  • 问题内容: 我正在尝试将一些JSON数据反序列化为应用程序的对象。到现在为止还不错,因为JSON数据上的属性是静态的(带有值的键)。现在,我得到了一个结果,其中的关键是动态数据。 这是一个示例JSON网址: http://en.wikipedia.org/w/api.php?action=query&format=json&pageids=6695&prop=info 由此产生的JSON是: 好的

  • 问题内容: 我的JSON有点弱,所以我需要一些帮助。 我正在尝试反序列化用户的JSON: 放入我用属性装饰的对象中: 我得到以下异常: Newtonsoft.Json.JsonSerializationException:在JSON中找不到必需的属性’user_id’。 这是因为JSON对象是一个数组吗?如果是这样,如何将其反序列化为一个User对象? 提前致谢! 问题答案: 正如Alexandr

  • 问题内容: 我正在尝试对a进行序列化/反序列化,如果对象是简单类型,这似乎很好,但是当对象更复杂时,它不起作用。 我有这个课: 在我的字典中,我添加了一个带有“重定向链”键的键和一些带有“状态”,“网址”,“父网址”键的简单字符串。我从JSON.Net返回的字符串如下所示: 我用来序列化的代码如下: 反序列化我正在做的事情: 字典恢复正常,所有字符串恢复正常,但是列表未正确反序列化。它只是作为 当

  • 问题内容: 我有一堂课 我想将下面的JSON数据反序列化到上面的类/对象中 我的想法是在JSON中是一个对象,但我只想获取(在JSON中)在反序列化期间将像在类中那样传递。 如何使用Json.NET实现该目标? 我相信我可以使用CustomJsonConverter完成它。但是我很困惑。docs中的示例仅用于,但不适用。 问题答案: 我只是使用上面在问题中提到的方法解决了我的问题。在我完整的代码下

  • 问题内容: 我正在使用以下类型定义Json.NET属性,然后在其方法内部使用Json.NET对其进行序列化: 我的问题是,它将返回“ {}”。这是为什么?以前在工作。我所做的唯一更改是更改了OptIn而不是OptOut,因为我希望包含的属性少于保留的属性。 问题答案: 如Newtonsoft在本期中所述,Json.NET实际上支持属性。但是,当相应的“真实”成员是属性时,似乎Json.NET要求成

  • 问题内容: 我有一个C#列表,看起来像这样: 我使用以下代码将JSON转换/序列化为(Newtonsoft.JSON): 使用上面的代码,我得到一个像这样的json字符串: 但是,这就是我需要得到的:由于我正在使用把手模板- 如何使用序列化器如上所述命名JSON数组? 问题答案: 用: