System.Text.Json中可以进行多态反序列化吗?
我尝试从Newtonsoft.Json迁移到System.Text.Json。我想反序列化抽象类。Newtonsoft.Json为此具有TypeNameHandling。有什么方法可以通过.net
core 3.0上的System.Text.Json反序列化抽象类?
回答:
System.Text.Json中可以进行多态反序列化吗?
答案是肯定的 没有,这取决于你的意思是什么 “可能” 。
有 多态的反序列化(相当于Newtonsoft.Json的TypeNameHandling
)支持
到System.Text.Json
。这是因为阅读指定为JSON有效载荷(如在一个字符串的.NET类型名称$type
是元数据属性)来创建你的对象
,因为它引入了潜在的安全隐患(见https://github.com/dotnet/corefx/ Issues /
41347#issuecomment-535779492了解更多信息)。
允许有效负载指定自己的类型信息是Web应用程序中漏洞的常见来源。
然而, 通过创建一个以增加自己的多态反序列化方式支持JsonConverter<T>
,所以在这个意义上说,这是可能的。
该文档显示了一个使用 属性的方法的示例:https : //docs.microsoft.com/zh-
cn/dotnet/standard/serialization/system-text-json-converters-how-to#support-
多态反序列化
让我们来看一个例子。
假设您有一个基类和几个派生类:
public class BaseClass{
public int Int { get; set; }
}
public class DerivedA : BaseClass
{
public string Str { get; set; }
}
public class DerivedB : BaseClass
{
public bool Bool { get; set; }
}
您可以创建以下代码JsonConverter<BaseClass>
,该代码在序列化时写入类型识别符,然后读取以识别要反序列化的类型。您可以在上注册该转换器JsonSerializerOptions
。
public class BaseClassConverter : JsonConverter<BaseClass>{
private enum TypeDiscriminator
{
BaseClass = 0,
DerivedA = 1,
DerivedB = 2
}
public override bool CanConvert(Type type)
{
return typeof(BaseClass).IsAssignableFrom(type);
}
public override BaseClass Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
if (!reader.Read()
|| reader.TokenType != JsonTokenType.PropertyName
|| reader.GetString() != "TypeDiscriminator")
{
throw new JsonException();
}
if (!reader.Read() || reader.TokenType != JsonTokenType.Number)
{
throw new JsonException();
}
BaseClass baseClass;
TypeDiscriminator typeDiscriminator = (TypeDiscriminator)reader.GetInt32();
switch (typeDiscriminator)
{
case TypeDiscriminator.DerivedA:
if (!reader.Read() || reader.GetString() != "TypeValue")
{
throw new JsonException();
}
if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
baseClass = (DerivedA)JsonSerializer.Deserialize(ref reader, typeof(DerivedA));
break;
case TypeDiscriminator.DerivedB:
if (!reader.Read() || reader.GetString() != "TypeValue")
{
throw new JsonException();
}
if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
baseClass = (DerivedB)JsonSerializer.Deserialize(ref reader, typeof(DerivedB));
break;
default:
throw new NotSupportedException();
}
if (!reader.Read() || reader.TokenType != JsonTokenType.EndObject)
{
throw new JsonException();
}
return baseClass;
}
public override void Write(
Utf8JsonWriter writer,
BaseClass value,
JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value is DerivedA derivedA)
{
writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.DerivedA);
writer.WritePropertyName("TypeValue");
JsonSerializer.Serialize(writer, derivedA);
}
else if (value is DerivedB derivedB)
{
writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.DerivedB);
writer.WritePropertyName("TypeValue");
JsonSerializer.Serialize(writer, derivedB);
}
else
{
throw new NotSupportedException();
}
writer.WriteEndObject();
}
}
这是序列化和反序列化的样子(包括与Newtonsoft.Json的比较):
private static void PolymorphicSupportComparison(){
var objects = new List<BaseClass> { new DerivedA(), new DerivedB() };
// Using: System.Text.Json
var options = new JsonSerializerOptions
{
Converters = { new BaseClassConverter() },
WriteIndented = true
};
string jsonString = JsonSerializer.Serialize(objects, options);
Console.WriteLine(jsonString);
/*
[
{
"TypeDiscriminator": 1,
"TypeValue": {
"Str": null,
"Int": 0
}
},
{
"TypeDiscriminator": 2,
"TypeValue": {
"Bool": false,
"Int": 0
}
}
]
*/
var roundTrip = JsonSerializer.Deserialize<List<BaseClass>>(jsonString, options);
// Using: Newtonsoft.Json
var settings = new Newtonsoft.Json.JsonSerializerSettings
{
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects,
Formatting = Newtonsoft.Json.Formatting.Indented
};
jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(objects, settings);
Console.WriteLine(jsonString);
/*
[
{
"$type": "PolymorphicSerialization.DerivedA, PolymorphicSerialization",
"Str": null,
"Int": 0
},
{
"$type": "PolymorphicSerialization.DerivedB, PolymorphicSerialization",
"Bool": false,
"Int": 0
}
]
*/
var originalList = JsonConvert.DeserializeObject<List<BaseClass>>(jsonString, settings);
Debug.Assert(originalList[0].GetType() == roundTrip[0].GetType());
}
以上是 System.Text.Json中可以进行多态反序列化吗? 的全部内容, 来源链接: utcz.com/qa/419791.html