[C#]MemoryPackを使ってみたい4 - MemoryPackableの色々

Cysharp/MemoryPack

基本的な機能を見てきてそれだけでも十分使えそうなのですが、さらにいろんな機能が用意されているので、様々な実戦に対応できるようになっています。

ちょっとさらっと順番に見ておこうと思います。

1. [MemoryPackable]

MemoryPackでシリアライズできるのは、class, struct, record, record struct, interfaceとまあ何でもいいんですが、structrecord structの場合は、後に挙げる機能は使えないので注意です。

プライベートな要素はシリアライズ/デシリアライズされません。

2. [MemoryPackIgnore]

パブリックな要素につけて置くことで、シリアライズ/デシリアライズされなくなります。

3. [MemoryPackInclude]

プライベートなフィールドやメンバ変数はそのままだと無視されますが、この属性をつけておけばちゃんとシリアライズ/デシリアライズされます。

ただし順番や型の制約は受けますので、コードフォーマッタなどでガチャッとやられると壊れますので注意が必要でしょう。

4. [MemoryPackAllowSerialize]

[MemoryPackable]のクラスのパブリックメンバーに、[MemoryPackable]でない型のメンバーを指定すると、「そのクラスはシリアライズできないぞ」というエラーが出てコンパイルできなくなります。

何らかの理由(そのフィールドだけ別のシリアライザが担当するとか)で、[MemoryPackable]でないクラスを使う場合は、この属性をつけておくことでエラーとして扱われなくなります。

5. [MemoryPackable(SerializeLayout.Explicit)]と[MemoryPackOrder]

コードの可読性などの影響で、どうしてもコード上のメンバー順と、シリアライズされる順番を変えたい場合は、クラスを[MemoryPackable(SerializeLayout.Explicit)]で指定して、メンバーに[MemoryPackOrder(0)]という風に順番を指定しておくことで、C#のコードの順番ではない位置に持って行くことができます。

6. [MemoryPackConstructor]

MemoryPackはいろんなコンストラクタパターンに対応しています。

コンストラクタに[MemoryPackConstructor]をつけておくと、デシリアライズ時にそのコンストラクタで処理されるようになります。

また、パラメータ付きのコンストラクタでも大丈夫ですが、その場合引数の名称をメンバー名と合わせておく必要があります(大文字小文字は無視)。

ルールとしてはこんな感じです。

例えば、C#側では生成時に特定のパラメータ指定で生成できるようにコンストラクタを用意するが、デシリアライズ時は全てのメンバーを普通に処理したい場合は、引数なしコンストラクタに[MemoryPackConstructor]をつけておく…とか言う感じでしょうか。

7. シリアライズ/デシリアライズ前後の処理

シリアライズ前後、デシリアライズ前後に、何らかの処理を挟むことができます。

パラメータなしのメソッド(public/privateどっちでも可、staticでもOK)に属性をつけるだけです。

ただし、[MemoryPackOnDeserializing](デシリアライズ前)については、staticメソッドではない場合、デシリアライズ先をref渡しした場合だけ実行されます。

var obj = new TestClass();
MemoryPackSerializer.Deserialize(buffer, ref obj);

みたいなパターンです。

var obj = MemoryPackSerializer.Deserialize<TestClass>(buffer);

のパターンでは、[MemoryPackOnDeserialized]だけ実行されることになります。

デバッグなどに使えそうですし、フィールドの値をチェックしたり補正したりするケースが考えられるでしょうか。

まとめ

他にも機能はあるんですが、その辺はなんかもうちょっと現実的なケースやデータで触ってみないと感触がつかめないので、また日を改めて書きたいと思います。