2013-07-21 1 views
4

Я использую ProtoBuf.NET для сериализации/десериализации некоторых классов. Я нахожу, что при десериализации я получаю поврежденный байт [] (дополнительные 0). Прежде чем спросить, да, мне нужно * WithLengthPrefix() версии АФИ Protobuf поскольку часть Protobuf находится в началах пользовательского потока :)ProtoBuf искажает массив байтов во время десериализации (добавлено 0 добавлено)

Во всяком случае, я вижу

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 являются в основном шестнадцатеричными 0x00 в base64.

Логика приложения похожа на

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] из образуют Parent конструктор в это Init() метод, Protobuf работает отлично. Однако у нас есть логика приложения, которая предотвращает это в реальной версии (по сравнению с тем, который вы видите выше).

Мы делаем что-то неправильно или это ошибка в ProtoBuf?

ответ

3

Здесь мы идем:

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

Примечание: Protobuf разработан (по Google), чтобы быть как appendable и объединяемы. Где append/merge является синонимом (для списков/массивов и т. Д.) С «append».

два варианта (как можно с помощью атрибутов):

  • отключают конструктор: [ProtoContract(SkipConstructor = true)]
  • отключить Append: [ProtoMember(1, OverwriteList = true)]

Есть и другие варианты тоже, но те из них, I наклонился.

Вы замечаете, что инициализация массива отличается от реального кода, но: я не могу комментировать код, который я не вижу.

+0

Инициализация довольно похожа, я имел в виду, что использование этого класса другими классами таково, что я не могу слишком сильно изменить подпрограммы ctor/init (по крайней мере, не без значительного рефакторинга). Thx для ответа, я скоро проверю его. – DeepSpace101

+0

@Sid и ни одна из показанных вещей не связана с изменением подпрограмм ctor/init –

Смежные вопросы