MemoryPackで同じ値をシリアライズしても同じバイト列にならないことがある

同じデータをシリアライズしているのに、バイト列が変わることがある問題に遭遇しました。

何が違っていたのか

原因はint?の未初期化パディング。
MemoryPackはメモリ配置をそのまま書き込むため、値が同じでもパディング部分のバイト列が変わることがあります。報告したIssue

例えば今回の環境では、int?には以下のように3バイトのパディングがありました。ここは規格上不定なので、何が入っていても文句は言えません。

hasValue   パディング   value
1バイト    3バイト      4バイト

MemoryPackはここも含めて書き込むので、バイト列が変わる、ということでした。
もちろんパディングは使わない領域なので、デシリアライズした結果は同じになります。

解決策

v1.22.0で追加されたSafeNullable<T>に置き換えることで対処できます。

- public int? IntValue { get; set; }
+ public SafeNullable<int> IntValue { get; set; }

int?以外にも、short?、long?、float?、double?、DateTime?、Guid?、decimal?など、パディングが入る型は注意。enum?は基底型によります。

また、独自のunmanaged structも内部にパディングがあれば同様です。こちらはSafeNullable<T>で包んでも内部のパディングまでは除去されません。実装