目录
前言
上回,我们讲解了《如何序列化派生类》。
那如何反序列化派生类呢?
假设有一个 Person 抽象基类,其中包含 Student 和 Teacher 派生类:
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int Score { get; set; }
}
public class Teacher : Person
{
public string Title { get; set; }
}
如果 API 输入类型是单个 Person 抽象基类,即使我们传入正确格式的派生类 JSON 字符串,System.Text.Json
也只会使用基类进行反序列化:
[HttpPost]
[Route("get")]
public string Get(Person person)
{
return person.GetType().ToString();
}
我们必须主动告诉System.Text.Json
如何处理反序列化派生类,因此需要自定义转换器。
思路
与序列化相反,我们需要实现自定义转换器的Read
方法:
public class PersonConverter : JsonConverter<Person>
{
public override Person Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
}
}
现在的关键是,如何判断到底要反序列化成哪个派生类型。
我们可以使用Read
方法遍历 JSON 的所有 Property, 找到对应派生类型独有的属性,即可知道当前需要反序列化成哪个派生类型。
实现
为基类创建自定义转换器,实现Read
方法:
public override Person Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Utf8JsonReader readerClone = reader;
while (readerClone.Read())
{
JsonTokenType tokenType = readerClone.TokenType;
switch (tokenType)
{
case JsonTokenType.PropertyName:
if (readerClone.ValueTextEquals("score"))
{
return (Person)JsonSerializer.Deserialize(ref reader,typeof(Student), options);
}
else if (readerClone.ValueTextEquals("title"))
{
return (Person)JsonSerializer.Deserialize(ref reader, typeof(Teacher), options);
}
break;
}
}
throw new NotImplementedException();
}
因为 Utf8JsonReader 是只进读取器,因此这里需要创建 Utf8JsonReader 实例的克隆readerClone
去遍历 JSON,而原始 reader 用于反序列化派生类。
然后修改 Startup.cs 文件,注册自定义转换器:
services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new PersonConverter()));
运行,反序列化成功:
结论
通过自定义转换器,我们实现了使用System.Text.Json
反序列化派生类。