1

我在 C++/CLI 中定义了一个类,如下所示:

literal Int32 BufferLength = 4000;

Message()
{
   num1 = 0;
   num2 = 0;
   str1 = String::Empty;
   buffer = gcnew array<System::SByte>(BufferLength);
};

[ProtoMember(1)]
property double num1
{
   double get() { return _num1; }
   void set(double value) { _num1 = value; }
}

[ProtoMember(2)]
property double num2
{
   double get() { return _num2; }
   void set(double value) { _num2 = value; }
}

[ProtoMember(3)]
property String^ str1
{
   String^ get() { return _str1; }
   void set(String^ value) { _str1 = value; }
}

[ProtoMember(4)]
property array<System::SByte>^ buffer
{
   array<System::SByte>^ get() { return _buffer; }
   void set(array<System::SByte>^ value) { _buffer = value; }
}

在调试时,我可以看到序列化程序从缓冲区属性中提取值,并且数据完好无损。当反序列化器运行时,我看到它将数据推送到缓冲区属性中,但是该数组填充了 0,而不是序列化之前存在的数据。我尝试在 ProtoMember 属性上设置 IsRequired = true ,但没​​有运气。

我有其他用 sbyte 数组定义的消息,这些消息可以很好地反序列化。但是,这些数组非常短(最多 10 个)。对我来说唯一突出的是这个数组的长度。帮助!:-)

编辑:我想我还应该提到我正在使用 v1 r282。

4

1 回答 1

1

这里的错误是protobuf-net(符合protobuf-spec)通过附加数据反序列化列表(等)数据。在“v1”(您正在使用的版本)中,它始终运行构造函数。因此,在反序列化时,它会运行构造函数(创建一个长度为 4000 的数组),然后处理数据并附加另外 4000 个项目。如果你检查一下,你会发现数组现在有 8000 长(你会很高兴听到它没有将数组大小调整 4000 次......)。

修复:

  • 在 v2 中(还没有完全发布,仅供参考),您可以完全禁止构造函数
  • 或者只是删除 ctor 中的数组创建,然后通过 set 进行分配(也许添加一个静态工厂方法来为您执行此操作,以节省一些代码)

以下测试台(为方便起见翻译成 C#,抱歉)工作正常:

using System;
using System.Diagnostics;
using ProtoBuf;

namespace ConsoleApplication28
{
    class Program
    {
        static void Main()
        {
            var msg = Message.Create();
            var rand = new Random();
            var buffer = msg.buffer;
            for (int i = 0; i < buffer.Length; i++)
                buffer[i] = (sbyte)rand.Next(-128, 128);
            var clone = Serializer.DeepClone(msg);
            var cloneBuffer = clone.buffer;
            Debug.Assert(!ReferenceEquals(buffer, cloneBuffer), "Should be different buffer");

            Debug.Assert(buffer.Length == cloneBuffer.Length, "Should be same length");
            for(int i = 0 ; i < buffer.Length ; i++)
                Debug.Assert(buffer[i] == cloneBuffer[i], "Should be same value at index " + i);
        }
    }

    [ProtoContract]
    public class Message
    {
        const int BufferLength = 4000;
        public static Message Create()
        {
            var msg = new Message();
            msg.buffer = new sbyte[BufferLength];
            return msg;
        }
        private Message()
        {
           num1 = 0;
           num2 = 0;
           str1 = String.Empty;
        }


        private double _num1, _num2;
        private string _str1;
        private sbyte[] _buffer;

        [ProtoMember(1)]
        public double num1
        {
            get { return _num1; }
            set { _num1 = value; }
        }

        [ProtoMember(2)]
        public double num2
        {
           get { return _num2; }
           set { _num2 = value; }
        }

        [ProtoMember(3)]
        public String str1
        {
           get { return _str1; }
           set { _str1 = value; }
        }

        [ProtoMember(4)]
        public sbyte[] buffer
        {
           get { return _buffer; }
           set { _buffer = value; }
        }    
    }
}
于 2010-08-19T21:00:24.187 回答