うーん、結構あるんですよね、状況に応じて複数データ返したいときって。愚直にやるとこうなるわけです。set;}}いやー、色々無駄だし型の表現としてもアレだしちょっと、ねー、っていう。Unionをシリアライザで記述するという点では、ZeroFormatterのやり方はかなり上手い感じで(自分で言う)、書きやすさと安全性(完全ではないけれど、意識しやすさが高いのでそこそこはある)をいい塩梅に両立させれたんじゃないかなー、と。書きやすさはかなりあると思います。いうかぶっちけ他のシリアライザでこの手のポリモーフィズムやるのは凄まじく大変なので、革命的に便利になったといっても過言ではない。諸々の追加や事情も踏まえて、バイナリ仕様を整理しました。Specificationまず、言語中立にしました。いやまぁ、もともと、C#依存度の高いものは外して移植しようと思えばできるように、みたいな感じに作ってはいたのですけれど、より明確に中立を意識して整理しました。Formatというのを正式に用意して遅延ではないDictionaryなどのレイアウトはここに属する、という形にしました。いう分けかたで定義して、KeyTupleはStructに属してますよ、みたいに割とそこそこちゃんと汎用的感な分類になってるんじゃあなかろうか。あーでもないこーでもないと弄ってたんですが、うーん、なるほど、こういうのは結果はあっさりしてるけど過程はとても大変......。いうわけで、言語がC#のみってのはさすがに普通に欠点なんですが、整備してみたんで多言語サポートよろしくお願いします、みたいな(?)。やりたい気持ちはあるんですが、如何せんちょっとC#以外は手が回らないのデスデス。社内ではサーバーもC#で完動するようになってるので、あんまり強い外圧が働かなくて。実際手が回らないので。仕様作る!実装する!社内のプロジェクトのデータの移植もする!更にこれを使った次の何かも作る!あわあわわわわあわ、本当に手が回ってないヤヴァイ。スキーマはあるよスキーマはあります。いうことかというとこういうことです。}}C#自体がスキーマなのです。Studio)の恩恵をフルに使える」ってのが、まずは良い。実際、zfc.exe(ZeroFormatterCompiler)という実行ファイルによって、C#というスキーマをもとにコード生成をしています。現在はAOTのためのC#コード生成ですが、別に出力を変えれば、他の言語のコードでも全然吐けます(ランタイムがないから無理だけど!)デメリットは「機能が制限されてないので容易に制限からはみだせるので言語中立にしづらい」「現行のC#の言語機能に制限される(例えば非nullなStringは定義できない)」ってとこですね。前者がビミョーなんですが紳士協定の範囲内(C#としてコンパイル可能でもZeroFormatterとして解析不能だっていうエラーを放り投げちゃえばSyntaxErrorなコードと変わらない)に収めることはなんとか可能なんじゃあないかなあ、とか。最大の利点がスキーマが生成を介さなくてもシェアできる、ということ。「プロジェクト参照」や「DLL参照」という形で、スキーマと生成コード(実際は実行時動的生成するんですが)をコード生成なしで複数プロジェクト間で共有できます。これは非常に大きくて、まぁ前の記事でも書いたんですがコード生成はやればやるほど複雑化していくんで、ないに越したことはないんですよね。Schemaだと、ゼロにできる。これはワークフローにとってはインパクトが相当大きいことです。私は、コード生成や自動化って「したくない」ことの筆頭候補に挙げてます。自動化はミクロでは楽になっても、その積み重ねがマクロでは害悪になるケースが往々にして多い。やるべきことは「自動化をしなくてすむ」ようにすることです。そのために脳みそを動かしたい。結果、脳みそが追いついてなくてそこら中が止まることも往々にしてある。Anythingやってます(とは)。Fastestとかぶち撒けたせいでシリアライザ戦争が勃発している(恐ろしい)。Wire、シランカッタ。コード的には基本的にZeroFormatterのほうが速そーなので、トータルで色々なケース作れば勝つと思うんだけど、弱点を突くと負けるケースは出てくるのかなぁ。いえ普通に私の手元で図ったら圧勝した、ふむ。圧倒的な圧勝ということで、まぁしょうがない、相手が悪い。確かにWireは二位なので、惜しかったで賞というところ)というわけで、真面目に、C#でサッと今使ってるシリアライザをそのまま置き換えられるものにしました。あらゆるところで使ってください、と言ってます。実際、小さなところから大きなところまで効果あると思います。小さなところは↑でstructを例にしましたが、大きなところでは、例えばバッチ処理の連鎖とかで、延々と巨大なデータを送っているのだけれど、一つ一つはその一部しか使わないんだよねー、みたいな場合。ものすごく効くんじゃない?って意見貰いました。その通りで、実際そういうケースでは正しくめっちゃ効きますねー。感なので、是非是非試してみてくださいな。(11/1423:01)大変助かりましたー。(11/1516:42)初めまして。githubの作法を知らない無作法者で失礼します。以下のコードでバグが出るようなのでご報告させていただきます。(11/1517:34)あー、すみません、シリアライズするとUniversalTimeで保存しデシリアライズ時には特にローカルタイムに戻さないので、日本でやると9時間遅れます。ToLocalTimeすることで日本時間に戻せますが、デシリアライズ時にローカルタイムに自動で戻すオプションは検討してもいいかもしれません。(11/1519:20)そもそも仕様のバグで、DateTimeOffsetにオフセット(時差)データを保存していませんでした......。いうわけで、正式に、時差も込みで記録・復元したい場合はDateTimeOffsetでの宣言をUTCで時間情報そのものだけを保存する場合はDateTimeでの宣言をという分け方にしました、というのをアップしました。(01/0911:47)ZeroFormatterのBinaryUtil中での処理について質問です。float/doubleへのRead/Writeではoffsetの剰余による分岐がありますが、intなどへのRead/Writeではoffsetの分岐なしにポインタ演算→間接参照しています。dereferenced.”とあり、アライメントが正しくない間接参照は未定義とあります。ような場合は未定義になりそうなのですが大丈夫なのでしょうか。coreclrのBitConverterの実装を見ますと、そちらではintなどでも分岐してWriteしていました。(01/0920:55)素晴らしい質問ありがとうございます、また、丁寧な参照助かります。大丈夫かどうかでいうと、正直悩ましくです......。挙動は完全に未定義で、CPUによりけりで変わってしまうのではないかと考えています。そのうえで、現実的に、現状.NETの動く環境では問題はでないと踏んでいるんですが(float/doubleで分岐しているのは、実際AndroidのCPUで問題が出たから......)大丈夫だと言い切れるかに関してはなんとも言い難いところです。安全寄りに倒すべき、な気はしています。