💻
Utf8JsonでDictionaryのキーにCustom Formatterを利用する
はじめに
.NETでJSONを扱うにあたり、Utf8Jsonというライブラリがあります。
UTF-8ネイティブな .NET用のJSONライブラリにはSystem.Text.Jsonもありますが、参照型を扱う場合にデフォルトコンストラクターが必要なことから、私はUtf8Jsonを使うことがあります。
ここではUtf8Json使う場合に、Dictionaryオブジェクトのキーに組み込み型ではない、自作のクラスや構造体を使う方法を紹介したいと思います。
対象の自作クラス
こんなImmutableなデフォルトコンストラクターを持たないクラスや構造体を、Dictionaryのキーに利用します。
public readonly struct EmployeeId
{
public EmployeeId(int intValue)
{
IntValue = intValue;
}
public int IntValue { get; }
}
Custom Formatterを作成する
Utf8Jsonでは独自クラスでJSONのシリアライズを明示的に指定したい場合、IJsonFormatterを実装する必要がありますが、Dictionaryのキーに利用する場合は、IJsonFormatterに追加してIObjectPropertyNameFormatterを実装する必要があります。
EmployeeIdの例では、intのプロパティのみをシリアライズ・デシリアライズしたいので、Formatterを次のように実装します。
このとき、JSONの仕様上、連想配列(Dictionary)のキーは文字列である必要があるため、それ以外での使用箇所とは別のシリアライズ・デシリアライズを利用できるよう、異なるインターフェイス、IObjectPropertyNameFormatterで変換を実装します。
public sealed class EmployeeIdFormatter : IJsonFormatter<EmployeeId>, IObjectPropertyNameFormatter<EmployeeId>
{
public void Serialize(ref JsonWriter writer, EmployeeId value, IJsonFormatterResolver formatterResolver)
{
writer.WriteInt32(value.IntValue);
}
public EmployeeId Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
{
return new EmployeeId(reader.ReadInt32());
}
public void SerializeToPropertyName(ref JsonWriter writer, EmployeeId value, IJsonFormatterResolver formatterResolver)
{
writer.WriteInt32(value.IntValue);
}
public EmployeeId DeserializeFromPropertyName(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
{
return new EmployeeId(reader.ReadString());
}
}
Custom Formatterを利用する
標準のFormatterに追加して、上記のFormatterを利用したい場合、つぎのように実装しましょう。
CompositeResolver.RegisterAndSetAsDefault(
new IJsonFormatter[] {new EmployeeIdFormatter()},
new[] {StandardResolver.Default});
var employeeNames = new Dictionary<EmployeeId, string>
{
[new EmployeeId(0)] = "Steve Jobs",
[new EmployeeId(1)] = "Bill Gates"
};
var jsonBytes = Utf8Json.JsonSerializer.Serialize(employeeNames);
これで次のようなJSONが得られます。
{0:"Steve Jobs",1:"Bill Gates"}
以上です。
Discussion