LoginSignup
2
1

More than 3 years have passed since last update.

Utf8JsonでDictionaryのキーにCustom Formatterを利用する

Last updated at Posted at 2020-09-23

はじめに

.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)のキーは文字列である必要があるため( @ktz_alias さんに指摘いただきました。ありがとうございました!)、異なるインターフェース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"}

以上です。

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1