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

回到顶部