如何解析 JSON 以获取从 Newtonsoft.Json 扩展 JObject 的 class 的类型化实例?

How to parse a JSON to get a typed instance of a class that extends JObject from Newtonsoft.Json?

我想使用继承从下载的库 (Newtonsoft json) 扩展 class。也许这不是最好的解决方案,但我想了解我错过了什么。

所以,这里是基本的概述 class 我想用额外的方法进行扩展: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JObject.htm

我创建了一个新的class,从基础class继承并实现构造函数:

public class JObjectTotalJiraTickets : JObject
{
    public JObjectTotalJiraTickets(string json) : base(json) { }
    public JObjectTotalJiraTickets(Object o) : base(o) { }
    public JObjectTotalJiraTickets(Object[] o) : base(o) { }
    public JObjectTotalJiraTickets(JObject jo) : base(jo) { }

    public void sayhello()
    {
        Console.WriteLine("Hello!");
    }

接下来,我创建新的 class 我的“自定义”实例 class:

// Here I get error CS0266 (Cannot implicitly convert type 'Newtonsoft.json.linq.JObject' to 'JObjectTotalJiraTickets)
// And propose IDE0002 (Name can be simplified), with the solution to change my type just to JObject class.
JObjectTotalJiraTickets o = JObjectTotalJiraTickets.Parse(json);

我误会了什么?使用 classes 我创建并完全控制 - 一切正常,但使用这个 - 它没有。

是的,我知道我可以像这样按类型投射,它会起作用

JObjectTotalJiraTickets o = (JObjectTotalJiraTickets)JObjectTotalJiraTickets.Parse(json);

但是为什么?为什么我不能在没有隐式转换的情况下继续?

演员表不起作用的原因是 Parse() return 是 JObject。即使 Parse() 在名为 JObjectTotalJiraTickets 的专门 JObject 上可用,这并不意味着它会突然 return 一个 JObjectTotalJiraTickets 而不是 JObject .

可能的修复

您可以创建一个新的 Parse() 方法来替换原来的方法,如下所示:

public class JObjectTotalJiraTickets : JObject
{
    public static new JObjectTotalJiraTickets Parse(string json)
    {
        // Re-use base class parse logic.
        var jobj = JObject.Parse(json);

        // Your logic to create a `JObjectTotalJiraTickets` from a `JObject`.
        JObjectTotalJiraTickets myjobj = DoTheJiraThings(jobj)

        return myjobj;
    }
}

请注意替换继承的 Parse() 方法的 new 修饰符。

事实上,如果您查看 JObject 的源代码,您会发现它的确如此 exactly that to replace/extend the parse logic it inherited from JToken

避免继承

请注意,继承几乎总是 the worst way to go。尽可能避免它并寻找不同的方法。

“但仍然...为什么转换不起作用?”

编译器试图告诉您假设每个 JObject 也总是一个 JObjectTotalJiraTickets 是没有意义的。这就像说每个 Animal 总是一个 Cat。这不仅是假的,而且还冒犯了猫。

然而,反过来说是有道理的:JObject o = new JObjectTotalJiraTickets() 这就像说每个 Cat 是一个 Animal.

通过显式转换 JObjectTotalJiraTickets o = (JObjectTotalJiraTickets)new JObject(),您实际上是在告诉编译器您知道得更多,并且您 100% 确定 JObject 实例实际上是一个 JObjectTotalJiraTickets。编译器会相信你,但转换会在运行时失败。