反序列化接口和抽象属性的一种方法是在序列化和反序列化期间将 TypeNameHandling 设置为 Auto。但是,当我在直接序列化和反序列化接口对象时尝试相同的方法时,它不起作用 -
interface ISample
{
string Key { get; set; }
}
class A : ISample
{
public string Key { get; set; }
public A(string key)
{
this.Key = key;
}
}
class B : ISample
{
public string Key { get; set; }
public B(string key)
{
this.Key = key;
}
}
序列化和反序列化代码 -
ISample a = new A("keyA");
ISample b = new B("keyB");
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;
var stringA = JsonConvert.SerializeObject(a, settings);
var stringB = JsonConvert.SerializeObject(b, settings);
Console.WriteLine(stringA);
Console.WriteLine(stringB);
a = JsonConvert.DeserializeObject<ISample>(stringA, settings);
b = JsonConvert.DeserializeObject<ISample>(stringB, settings);
我注意到,即使在设置 TypeNameHandling.Auto 时,序列化字符串中也不存在类型信息。但是,将"类型名称处理"设置为"对象"或"全部"有效。
我在这里错过了一些基本的东西吗?
要在根级别为具有TypeNameHandling.Auto
的多态对象启用$type
信息的输出,请使用以下重载:JsonConvert.SerializeObject Method (Object, Type, JsonSerializerSettings)
。 从文档中:
public static string SerializeObject( Object value, Type type, JsonSerializerSettings settings )
类型 类型:系统型 要序列化的值的类型。当"类型名称处理"为"自动"时,使用此参数在值的类型不匹配时写出类型名称。指定类型是可选的。
在您的情况下,您将执行以下操作:
var stringA = JsonConvert.SerializeObject(a, typeof(ISample), settings);
var stringB = JsonConvert.SerializeObject(b, typeof(ISample), settings);
Console.WriteLine(stringA);
Console.WriteLine(stringB);
并得到结果:
{"$type":"Tile.TestJsonDotNet.A, Tile","Key":"keyA"}
{"$type":"Tile.TestJsonDotNet.B, Tile","Key":"keyB"}
请注意Newtonsoft文档中的这一警告:
当应用程序从外部源反序列化 JSON 时,应谨慎使用类型名称处理。使用非 None 的值反序列化时,应使用自定义序列化绑定程序验证传入类型。
有关为什么可能需要这样做的讨论,请参阅 Newtonsoft Json 中的 TypeNameHandling 警告、如何配置 Json.NET 以创建易受攻击的 Web API 以及 Alvaro Muñoz & Oleksandr Mirosh 的黑帽论文 https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf