该库包含在 .NET Core 3.1 及更高版本的运行时中。System.Text.Json 比常用的 Newtonsoft.Json 快得多。System.Text.Json
但是,System.Text.Json 和 Newtonsoft.Json 之间存在一些重大更改。Microsoft 的此页面列出了它们之间的所有差异。多态序列化/反序列化就是其中之一。
在 Newtonsoft.Json 中,会自动处理多态序列化。尽管没有对多态反序列化的开箱即用支持,但可以使用 nuget 包 JsonSubTypes 来执行此操作。有关如何将 JsonSubTypes 与 Newtonsoft.Json 一起使用的详细信息。
但是,在 System.Text.Json 中,不直接支持多态序列化/反序列化。Microsoft 站点中介绍了几种解决方法。本文将重点介绍如何使用自定义 JsonConverter 实现多态序列化/反序列化。
首先,让我们定义具有继承关系的模型。
using System.Text.Json.Serialization;
using SystemTextJsonPolymorphism;
namespace IO.Swagger.Model
{
/// <summary>
/// Person
/// </summary>
public partial class Person
{
public Person() { }
/// <summary>
/// Gets or Sets Pet
/// </summary>
[JsonPropertyName("pet")]
public BasePet Pet { get; set; }
/// <summary>
/// Gets or Sets FullName
/// </summary>
[JsonPropertyName("fullName")]
public string FullName { get; set; }
}
/// <summary>
/// BasePet
/// </summary>
[JsonConverter(typeof(PetConverter))]
public abstract class BasePet
{
public BasePet() { }
/// <summary>
/// Gets or Sets Name
/// </summary>
[JsonPropertyName("name")]
public string Name { get; set; }
/// <summary>
/// Gets or Sets PetType
/// </summary>
[JsonPropertyName("typeDiscriminator")]
public string TypeDiscriminator { get; set; }
}
/// <summary>
/// Cat
/// </summary>
public partial class Cat : BasePet
{
public Cat() { }
/// <summary>
/// Gets or Sets Meow
/// </summary>
[JsonPropertyName("meow")]
public string Meow { get; set; }
}
/// <summary>
/// Dog
/// </summary>
public partial class Dog : BasePet
{
public Dog() { }
/// <summary>
/// Gets or Sets Bark
/// </summary>
[JsonPropertyName("bark")]
public string Bark { get; set; }
}
}
具有继承关系的对象
接下来,我们将定义一个继承自 JsonConverter
using IO.Swagger.Model;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonPolymorphism
{
internal class PetConverter : JsonConverter<BasePet>
{
public override bool CanConvert(Type typeToConvert) => typeof(BasePet).IsAssignableFrom(typeToConvert);
public override BasePet Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
using (var jsonDocument = JsonDocument.ParseValue(ref reader))
{
if (!jsonDocument.RootElement.TryGetProperty("typeDiscriminator", out var typeProperty))
{
throw new JsonException();
}
var jsonPet = jsonDocument.RootElement.GetRawText();
switch (typeProperty.GetString())
{
case "Cat":
return (Cat)JsonSerializer.Deserialize(jsonPet, typeof(Cat));
case "Dog":
return (Dog)JsonSerializer.Deserialize(jsonPet, typeof(Dog));
default:
throw new JsonException();
};
}
}
public override void Write(
Utf8JsonWriter writer, BasePet pet, JsonSerializerOptions options)
{
if (pet is Cat cat)
{
JsonSerializer.Serialize(writer, cat);
}
else if (pet is Dog dog)
{
JsonSerializer.Serialize(writer, dog);
}
}
}
}
这就是我们在 System.Text.Json 中实现多态序列化和反序列化所需要做的全部工作。以下代码片段显示了我们如何使用它和结果。
using System;
using IO.Swagger.Model;
using System.Text.Json;
namespace ConsoleAppNetCore
{
class Program
{
static void Main(string[] args)
{
const string jsonPerson1 = @"{
""fullName"": ""John Smith1"",
""Pet"": {
""name"": ""PetCat"",
""typeDiscriminator"": ""Cat"",
""meow"": ""Meow""
}
}";
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNameCaseInsensitive = true,
};
var person1 = new Person()
{
FullName = "John Smith1",
Pet = new Cat()
{
Name = "PetCat",
TypeDiscriminator = "Cat",
Meow = "Meow"
}
};
var person2 = new Person()
{
FullName = "John Smith2",
Pet = new Dog()
{
Name = "PetDog",
TypeDiscriminator = "Dog",
Bark = "Bark"
}
};
var jsonString1 = JsonSerializer.Serialize(person1, options);
var jsonString2 = JsonSerializer.Serialize(person2, options);
Console.WriteLine(jsonString1);
Console.WriteLine(jsonString2);
var person1_1 = JsonSerializer.Deserialize<Person>(jsonPerson1);
var person2_1 = JsonSerializer.Deserialize<Person>(jsonString2);
jsonString1 = JsonSerializer.Serialize(person1, options);
jsonString2 = JsonSerializer.Serialize(person2, options);
Console.WriteLine(jsonString1);
Console.WriteLine(jsonString2);
Console.ReadKey();
}
}
}
以下是运行 Program.cs 的结果。它演示了 pet 属性(Cat 或 Dog 类型)可以成功序列化和反序列化。