[C#]MemoryPackを使ってみたい5 - VersionTolerant

Cysharp/MemoryPack

11/10にver1.5.0がリリースされました。

MemoryPackを使ってみたい1 - 基本 の注意事項で、フィールドに関する制限がいくつかありましたが、それを緩和する機がはいりました。

Version tolerant

GenerateType.VersionTolerant

MemoryPackable属性をつけるときに、MemoryPackable(GenerateType.VersionTolerant)とGenerateTypeを指定して、各フィールドにMemoryPackOrderをちゃんとつけます。

[MemoryPackable(GenerateType.VersionTolerant)]
public partial class TestClass
{
    [MemoryPackOrder(0)]
    public int Id { get; set; }

    [MemoryPackOrder(1)]
    public string Name { get; set; } = default!;
}

で、もしこのクラスの仕様が変わって、FirstNameとLastNameにわけようってことになった場合、

[MemoryPackable(GenerateType.VersionTolerant)]
public partial class TestClass
{
    [MemoryPackOrder(0)]
    public int Id { get; set; }

    [MemoryPackOrder(1)]
    public string Name { get; set; } = default!;
}

[MemoryPackable(GenerateType.VersionTolerant)]
public partial class TestClassVer2
{
    [MemoryPackOrder(0)]
    public int Id { get; set; }
    
    //[MemoryPackOrder(1)]
    //public string Name { get; set; } = default!;

    [MemoryPackOrder(2)]
    public string FirstName { get; set; } = default!;
    [MemoryPackOrder(3)]
    public string LastName { get; set; } = default!;
}

という感じで、定義を変更した別バージョンのクラスを用意することで、TestClass <-> TestClassVer2で相互にシリアライズ/デシリアライズしてくれるようになります。

そのときのルールは下記の通り。

シリアライザの仕様的に「フィールドの順番に値だけきちきち詰めていく」ということなので、MemoryPackOrderで順番を固定してその順番の型を同じにしておけば、削除されたところや増えたところは適切に無視してくれるようになるわけです。

その代わりちょっとだけ処理に時間がかかるし、バイナリのサイズも大きくなるよということですが、元々が早いし一般的なサーバーとのやりとりであれば微々たるものでしょう。

まとめ

非常に実用的な機能が入りました。

運用中のシステムであってもデータの仕様が変わるのはよくある話なので、それにも対応しやすくなるのはいいことです。