Json.net序列化/反序列化派生类型?


98

json.net(newtonsoft)
我正在浏览文档,但找不到任何有关此方法或最佳方法的信息。

public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

JsonConvert.Deserialize<List<Base>>(text);

现在,序列化列表中有Derived对象。如何反序列化列表并获取派生类型?


继承不是这样工作的。您可以指定JsonConvert.Deserialize <Derived>(text); 包括名称字段。由于Derived 是一个 Base(反之亦然),因此Base对Derived的定义一无所知。
M.Babcock 2011年

对不起,澄清了一下。问题是我有一个包含基础对象和派生对象的列表。因此,我需要弄清楚如何告诉newtonsoft如何反序列化派生项。
威尔

我解决了这个问题。我有同样的问题
路易斯·卡洛斯·查瓦里亚

Answers:


46

如果要在您的类型中存储类型text(在这种情况下应该如此),则可以使用JsonSerializerSettings

请参阅:如何使用Newtonsoft JSON.NET将JSON反序列化为IEnumerable <BaseType>

不过要小心。使用除TypeNameHandling = TypeNameHandling.None可能导致安全漏洞之外的任何方法


24
您也可以使用TypeNameHandling = TypeNameHandling.Auto-这只会$type为声明的类型(即Base)与实例类型(即Derived)不匹配的实例添加属性。这样,您的JSON不会像一样膨胀TypeNameHandling.All
AJ理查森2015年

我不断收到JSON'...,...'中指定的错误解决类型。路径'$ type',第1行,位置82。有什么想法吗?
briba

3
在公共端点上使用此选项时要小心,因为它会带来安全问题:alphabot.com/security/blog/2017/net/…–
gjvdkamp

1
@gjvdkamp JEEZ对此表示感谢,对此我一无所知。将添加到我的帖子中。
kamranicus

96

您必须启用“类型名称处理”,并将其作为设置参数传递给(反)序列化器。

Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);

这将导致派生类的正确反序列化。它的一个缺点是它将命名您正在使用的所有对象,因此它将命名您要放入对象的列表。


31
+1。我搜索了30分钟,直到我真正发现您需要对SerializeObject和DeserializeObject使用相同的设置。我以为如果反序列化时它存在,它将隐式使用$ type,这真是愚蠢。
Erti-Chris Eelmaa 2015年

24
TypeNameHandling.Auto也会这样做,并且更好,因为当它与字段/属性的类型匹配时,它不写实例类型名称,大多数字段/属性通常是这种情况。
罗曼·斯塔科夫

2
在另一个解决方案/项目上执行反序列化时,此功能不起作用。序列化后,解决方案的名称将作为类型嵌入:“ SOLUTIONNAME.Models.Model”。在其他解决方案上进行反序列化时,它将引发“ JsonSerializationException:无法加载程序集'SOLUTIONNAME'。”
Sad CRUD Developer

19

由于这个问题非常普遍,因此如果您想控制类型属性名称及其值,添加一些操作可能会很有用。

很长的路要走,那就是编写custom JsonConverter来通过手动检查和设置type属性来处理(反序列化)。

一种更简单的方法是使用JsonSubTypes,它通过属性处理所有样板:

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}

3
我有需要,但我不喜欢必须让基类知道所有“ KnownSubType” ...
Matt Knowles

2
如果您查看文档,还有其他选择。我只提供了我更喜欢的示例。
rzippo

1
这是更安全的方法,不会在反序列化时公开您的服务以加载任意类型。
David Burg

3

使用此JsonKnownTypes,它的使用方法非常相似,它只是将鉴别添加到json:

[JsonConverter(typeof(JsonKnownTypeConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

现在,当你序列化JSON对象将增加"$type""base""derived"价值,这将是使用了反序列化

序列化列表示例:

[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.