前言
上回,我们讲解了《如何序列化派生类》。
那如何反序列化派生类呢?
假设有一个 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
反序列化派生类。
添加微信号【MyIO666】,邀你加入技术交流群