JSON 多型序列化紀錄
JSON polytype serialization, System.Text.Json, JsonElement, JsonSerializer
引言
工作紀錄以未來使用。
應用情境
流程圖(FlowDiagram)數據的序列化以存檔/載入的永續性應用。 FlowDiagram 內容物有 NodeList 與 LinkList 的集合。以程式碼表示如下:
class FlowDiagram {
public List<NodeBase> NodeList; // 多型集合
public List<LinkBase> LinkList; // 也是多型集合
}
NodeBase
只是基礎抽象類別,實體類別有:InitialNode
,EndNode
,ActivityNode
等等。
LinkBase
也是基礎抽象類別,實體類別有:GeneralLink
, ConditionLink
等等。
一些過程說明
預設不支援多型。不管是 JSON 還是 XML 都是不直接支援多型的。若有此需求一定有客製化或(不相同的)進階組態。近幾年都用 JSON 序列化早已確認不支援多型。以為 XML 序列化可以預設處理多型,花費約一個小時查找確定並不直接支援。
然若是有限度的多型序列化,只要一些客製化加工就能滿足需求。 本案例使用 System.Text.Json 實作。下面是案例說明。
關鍵說明-JSON多型序列化
經測試,JSON多型序列化是可以簡單做到的。只要改以"object"型別放置就可以"多型序列化"。上述案例改寫成:
class FlowDiagram {
public List<object> NodeList; // 多型集合
public List<object> LinkList; // 也是多型集合
}
//# 以 object type 序列化就有『多型序列化』的效果
FlowDiagram repo = new() { ... };
string json = JsonSerializer.Serialize(repo, options);
JSON 序列化時若發現來源是 object 時會用 GetType() 去取真實的 Type 再序列化,這樣等同多型序列化的效果。
關鍵說明-JSON多型反序列化
要進行反序列化有個關鍵之一就是要如何判定真實的 Type 為誰。簡單的方法就是在序列化時多填入它的 "Class" 識別名稱在之後反序列化時解開。反序列化成功的關鍵之二,若用 object type 解 JSON 封包就會解成 JsonElement type,這樣的好處是只要知到真實 Type 就能反序列化到其真實型別。
反序列化遇到object
就會產生JsonElement
實體,經判定出正確的型別再反序列化即可。
DiagramRepo derepo = JsonSerializer.Deserialize<DiagramRepo>(json);
//※ 反序列化遇到object就會產生JsonElement實體,經判定出正確的型別再反序列化即可。
for (int i = 0; i < derepo.NodeList.Count; i++)
{
JsonElement element = (JsonElement)derepo.NodeList[i];
// 取出預先標記的真實實體類別
string nodeClass = element.GetProperty("Class").GetString();
// 依正確的型別反序列化並回填。
derepo.NodeList[i] = nodeClass switch
{
"Initial" => element.Deserialize<InitialNode>(),
"End" => element.Deserialize<EndNode>(),
"Activity" => element.Deserialize<ActivityNode>(),
_ => element
};
}
原始碼
參考文件
Last updated