5

一部のクラスをシリアル化/逆シリアル化するために ProtoBuf.NET を使用しています。デシリアライズすると、破損した byte[] (余分な 0) が得られることがわかりました。あなたが尋ねる前に、はい、ProtoBuf API の*WithLengthPrefix()バージョンが必要です。なぜなら、ProtoBuf 部分はカスタム ストリームの先頭にあるからです :)

とにかく、わかりました

Original object is (JSON depiction):
{"ByteArray":"M+B6q+PXNuF8P5hl","ByteArray2":"DmErxVQ2y87IypSRcfxcWA==","K":2,"V
":1.0}

Protobuf: Raw Hex (42 bytes):
29-2A-20-0A-0C-33-E0-7A-AB-E3-D7-36-E1-7C-3F-98-65-12-10-0E-61-2B-C5-54-36-CB-CE
-C8-CA-94-91-71-FC-5C-58-08-02-15-00-00-80-3F

Regenerated object is (JSON depiction):
{"ByteArray":"AAAAAAAAAAAAAAAAM+B6q+PXNuF8P5hl","ByteArray2":"DmErxVQ2y87IypSRcf
xcWA==","K":2,"V":1.0}

メンバーのエクストラAAA*Aは、ByteArray基本的に base64 の 16 進数の 0x00 です。

アプリのロジックは次のようになります

static void Main(string[] args)
{
    var parent = new Parent();
    parent.Init();

    Console.WriteLine("\nOriginal object is (JSON depiction):");
    Console.WriteLine(JsonConvert.SerializeObject(parent));

    using (var ms = new MemoryStream())
    {
        Serializer.SerializeWithLengthPrefix(ms, parent, PrefixStyle.Base128);
        byte[] bytes2 = ms.ToArray();
        var hex2 = BitConverter.ToString(bytes2);
        Console.WriteLine("\nProtobuf: Hex ({0} bytes):\n{1}", bytes2.Length, hex2);

        ms.Seek(0, SeekOrigin.Begin);
        var backFirst = Serializer.DeserializeWithLengthPrefix<Parent>(ms,PrefixStyle.Base128);

        Console.WriteLine("\nRegenerated object is (JSON depiction):");
        Console.WriteLine(JsonConvert.SerializeObject(backFirst));
    }
}

DTO クラスは次のとおりです。

[DataContract]
[ProtoContract]
internal class Parent : Child
{
    [DataMember(Name = "ByteArray", Order = 10)]
    [ProtoMember(1)]
    public byte[] ByteArray { get; set; }

    [DataMember(Name = "ByteArray2", Order = 30, EmitDefaultValue = false)]
    [ProtoMember(2)]
    public byte[] ByteArray2 { get; set; }

    public Parent()
    {
        ByteArray = new byte[12];
    }

    internal void Init(bool bindRow = false)
    {
        base.Init();
        var rng = new RNGCryptoServiceProvider();
        rng.GetBytes(ByteArray);

        ByteArray2 = new byte[16];
        rng.GetBytes(ByteArray2);
    }
}

[DataContract]
[ProtoContract]
[ProtoInclude(5, typeof(Parent))]
public class Child
{
    [DataMember(Name = "K", Order = 100)]
    [ProtoMember(1)]
    public Int32 K { get; set; }

    [DataMember(Name = "V", Order = 110)]
    [ProtoMember(2)]
    public float V { get; set; }

    internal void Init()
    {
        K = 2;
        V = 1.0f;
    }
}

コンストラクターからそのメソッドに移動ByteArray = new byte[12]すると、ProtoBuf が正常に動作することがわかります。ただし、実際のバージョンではそれを防ぐアプリ ロジックがあります (上記の SO トリム ダウン コードとは異なります)。ParentInit()

何か間違っているのでしょうか、それとも ProtoBuf のバグですか?

4

2 に答える 2