前言
上回,我們講解了《如何序列化派生類》。
那如何反序列化派生類呢?
假設有一個 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】,邀你加入技術交流群