文档展示了如何使用类型鉴别器属性执行此操作的示例:https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#support-polymorphic-deserialization让我们看一个例子.假设您有一个基类和几个派生类:公共类 BaseClass{公共 int 整数 { 得到;放;}}公共类 DerivedA : BaseClass{公共字符串 Str { 获取;放;}}公共类 DerivedB : BaseClass{公共布尔布尔{得到;放;}}您可以创建以下 JsonConverter,它在序列化时写入类型鉴别器并读取它以确定要反序列化的类型.您可以在 JsonSerializerOptions 上注册该转换器.公共类 BaseClassConverter : JsonConverter{私有枚举类型鉴别器{基类 = 0,派生 A = 1,派生dB = 2}public override bool CanConvert(类型类型){返回 typeof(BaseClass).IsAssignableFrom(type);}公共覆盖基类读取(参考 Utf8JsonReader 阅读器,类型类型转换,JsonSerializerOptions 选项){if (reader.TokenType != JsonTokenType.StartObject){抛出新的 JsonException();}如果 (!reader.Read()||reader.TokenType != JsonTokenType.PropertyName||reader.GetString() != "TypeDiscriminator"){抛出新的 JsonException();}if (!reader.Read() || reader.TokenType != JsonTokenType.Number){抛出新的 JsonException();}基类基类;TypeDiscriminator typeDiscriminator = (TypeDiscriminator)reader.GetInt32();开关(类型鉴别器){case TypeDiscriminator.DerivedA:if (!reader.Read() || reader.GetString() != "TypeValue"){抛出新的 JsonException();}if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject){抛出新的 JsonException();}baseClass = (DerivedA)JsonSerializer.Deserialize(ref reader, typeof(DerivedA));休息;case TypeDiscriminator.DerivedB:if (!reader.Read() || reader.GetString() != "TypeValue"){抛出新的 JsonException();}if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject){抛出新的 JsonException();}baseClass = (DerivedB)JsonSerializer.Deserialize(ref reader, typeof(DerivedB));休息;默认:抛出新的 NotSupportedException();}if (!reader.Read() || reader.TokenType != JsonTokenType.EndObject){抛出新的 JsonException();}返回基类;}公共覆盖无效写入(utf8JsonWriter 作家,基类值,JsonSerializerOptions 选项){writer.WriteStartObject();如果(值是 DerivedAderivedA){writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.DerivedA);writer.WritePropertyName("TypeValue");JsonSerializer.Serialize(writer,derivedA);}else if (值是DeriveddB衍生B){writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.DerivedB);writer.WritePropertyName("TypeValue");JsonSerializer.Serialize(编写器,派生B);}别的{抛出新的 NotSupportedException();}writer.WriteEndObject();}}这是序列化和反序列化的样子(包括与 Newtonsoft.Json 的比较):private static void PolymorphicSupportComparison(){var objects = new List{ new DerivedA(), new DerivedB() };//使用:System.Text.Jsonvar 选项 = 新的 JsonSerializerOptions{转换器 = { new BaseClassConverter() },WriteIndented = 真};字符串 jsonString = JsonSerializer.Serialize(objects, options);Console.WriteLine(jsonString);/*[{类型鉴别器":1,类型值":{Str":空,内部":0}},{类型鉴别器":2,类型值":{布尔":假,内部":0}}]*/var roundTrip = JsonSerializer.Deserialize>(jsonString, options);//使用:Newtonsoft.Jsonvar 设置 = 新 Newtonsoft.Json.JsonSerializerSettings{TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects,格式 = Newtonsoft.Json.Formatting.Indented};jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(objects, settings);Console.WriteLine(jsonString);/*[{"$type": "PolymorphicSerialization.DerivedA, PolymorphicSerialization",Str":空,内部":0},{"$type": "PolymorphicSerialization.DerivedB, PolymorphicSerialization",布尔":假,内部":0}]*/var originalList = JsonConvert.DeserializeObject>(jsonString, settings);Debug.Assert(originalList[0].GetType() == roundTrip[0].GetType());}这是另一个 StackOverflow 问题,它展示了如何使用接口(而不是抽象类)支持多态反序列化,但类似的解决方案适用于任何多态:有吗在 System.Text.Json 的自定义转换器中手动序列化/反序列化子对象的简单方法?I try to migrate from Newtonsoft.Json to System.Text.Json.I want to deserialize abstract class. Newtonsoft.Json has TypeNameHandling for this.Is there any way to deserialize abstract class via System.Text.Json on .net core 3.0? 解决方案 The answer is yes and no, depending on what you mean by "possible".There is no polymorphic deserialization (equivalent to Newtonsoft.Json's TypeNameHandling) support built-in to System.Text.Json. This is because reading the .NET type name specified as a string within the JSON payload (such as $type metadata property) to create your objects is not recommended since it introduces potential security concerns (see https://github.com/dotnet/corefx/issues/41347#issuecomment-535779492 for more info).However, there is a way to add your own support for polymorphic deserialization by creating a JsonConverter<T>, so in that sense, it is possible.The docs show an example of how to do that using a type discriminator property:https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#support-polymorphic-deserializationLet's look at an example.Say you have a base class and a couple of derived classes: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; }}You can create the following JsonConverter<BaseClass> that writes the type discriminator while serializing and reads it to figure out which type to deserialize. You can register that converter on the 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(); }}This is what serialization and deserialization would look like (including comparison with 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());}Here's another StackOverflow question that shows how to support polymorphic deserialization with interfaces (rather than abstract classes), but a similar solution would apply for any polymorphism:Is there a simple way to manually serialize/deserialize child objects in a custom converter in System.Text.Json? 这篇关于System.Text.Json 中是否可以进行多态反序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-06 19:24