在使用 System.Text.Json 進行 JSON 序列化和反序列化操作時,我們會遇到一個問題:如何處理字典中的 Key 為自定義類型的問題。
背景說明
例如,我們有如下代碼:
//?定義一個自定義類型
public?class?CustomType
{public?int?Id?{?get;?set;?}public?string?Name?{?get;?set;?}//?獲取字符串表示的?Keypublic?string?Key?=>?$"{Id}_{Name}";
}//?定義一個?Dictionary<CustomType,?string>?類型的對象
Dictionary<CustomType,?string>?dictionary?=?new?Dictionary<CustomType,?string>
{{?new?CustomType?{?Id?=?1,?Name?=?"one"?},?"one"?},{?new?CustomType?{?Id?=?2,?Name?=?"two"?},?"two"?}
};//?序列化字典
string?json?=?JsonSerializer.Serialize(dictionary);//?反序列化字典
Dictionary<CustomType,?string>?dictionary2?=?JsonSerializer.Deserialize<Dictionary<CustomType,?string>>(json);
在上述代碼中,我們定義了一個自定義類型 CustomType,并使用這個類型作為 Dictionary 的 Key 類型。
接下來,我們使用 JsonSerializer.Serialize 方法將字典序列化為 JSON 字符串,并使用 JsonSerializer.Deserialize 方法將 JSON 字符串反序列化為字典。
但是,在上述代碼中,我們會發現,序列化字典時,字典中的 Key 會被序列化為一個 JSON 對象,而不是我們想要的字符串。
同樣的,在反序列化 JSON 字符串時,JSON 對象中的 Key 會被反序列化為一個 CustomType 類型的對象,而不是我們想要的字符串。
這時,我們就需要使用一個自定義的 JSON 轉換器來解決這個問題。
代碼示例
首先,我們定義一個繼承自 JsonConverter的類型 CustomTypeConverter,該類型實現了 Read、Write、ReadAsPropertyName、WriteAsPropertyName 方法:
public?class?CustomTypeConverter?:?JsonConverter<CustomType>
{public?override?CustomType?Read(ref?Utf8JsonReader?reader,?Type?typeToConvert,?JsonSerializerOptions?options){//?Deserialize?objectreturn?JsonSerializer.Deserialize<CustomType>(ref?reader,?options);}public?override?void?Write(Utf8JsonWriter?writer,?CustomType?value,?JsonSerializerOptions?options){//?Serialize?objectJsonSerializer.Serialize(writer,?value,?options);}public?override?CustomType?ReadAsPropertyName(ref?Utf8JsonReader?reader,?Type?typeToConvert,?JsonSerializerOptions?options){//?Read?key?as?stringvar?stringValue?=?reader.GetString();//?Parse?string?to?CustomTypereturn?ParseCustomType(stringValue);}public?override?void?WriteAsPropertyName(Utf8JsonWriter?writer,?CustomType?value,?JsonSerializerOptions?options){//?Write?key?as?stringwriter.WritePropertyName(value.Key);}private?CustomType?ParseCustomType(string?value){//?Parse?string?to?CustomTypevar?parts?=?value.Split("_");var?id?=?int.Parse(parts[0]);var?name?=?parts[1];return?new?CustomType{Id?=?id,Name?=?name};}
}
在上述代碼中,我們將 CustomType 類型的 Key 屬性作為字典的 Key,在序列化操作中,將 Key 屬性序列化為字符串,并在反序列化操作中,將字符串反序列化為 Key 屬性。
接下來,我們使用這個自定義的 JSON 轉換器來序列化和反序列化字典:
//?定義一個自定義類型
public?class?CustomType
{public?int?Id?{?get;?set;?}public?string?Name?{?get;?set;?}//?獲取字符串表示的?Keypublic?string?Key?=>?$"{Id}_{Name}";
}//?定義一個?Dictionary<CustomType,?string>?類型的對象
Dictionary<CustomType,?string>?dictionary?=?new?Dictionary<CustomType,?string>
{{?new?CustomType?{?Id?=?1,?Name?=?"one"?},?"one"?},{?new?CustomType?{?Id?=?2,?Name?=?"two"?},?"two"?}
};//?創建?JsonSerializerOptions?對象
var?options?=?new?JsonSerializerOptions();//?添加自定義的?JSON?轉換器
options.
Converters.Add(new?CustomTypeConverter());//?序列化字典
string?jsonString?=?JsonSerializer.Serialize(dictionary,?options);//?反序列化?JSON?字符串
var?result?=?JsonSerializer.Deserialize<Dictionary<CustomType,?string>>(jsonString,?options);
在上述代碼中,我們將 CustomType 類型的 Key 屬性作為字典的 Key,在序列化操作中,將 Key 屬性序列化為字符串,并在反序列化操作中,將字符串反序列化為 Key 屬性。
使用建議
在使用 System.Text.Json 進行序列化和反序列化操作時,如果要處理字典中 Key 為自定義類型的問題,可以通過定義一個自定義的 JSON 轉換器來解決。
在定義自定義的 JSON 轉換器時,需要注意以下幾點:
類型需要繼承自 JsonConverter類型。
類型需要實現 Read、Write、ReadAsPropertyName、WriteAsPropertyName 方法。
在 Read 方法中,需要將 JSON 字符串反序列化為 T 類型。
在 Write 方法中,需要將 T 類型序列化為 JSON 字符串。
在 ReadAsPropertyName 方法中,需要將 JSON 字符串反序列化為字典的 Key 屬性。
在 WriteAsPropertyName 方法中,需要將字典的 Key 屬性序列化為 JSON 字符串。
總結
本文通過一個實例,介紹了如何使用 System.Text.Json 進行序列化和反序列化操作時,處理字典中 Key 為自定義類型的問題。
在定義自定義的 JSON 轉換器時,需要注意類型需要繼承自 JsonConverter類型,并實現 Read、Write、ReadAsPropertyName、WriteAsPropertyName 方法。
參考資料
System.Text.Json
How to serialize and deserialize a dictionary with a custom key type
本文采用 Chat OpenAI 輔助注水澆筑而成,如有雷同,完全有可能。