protobuf-net 未反序列化 sbyte 数组

发布于 2024-09-15 07:24:19 字数 1036 浏览 10 评论 0原文

我在 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。

I have a class defined in C++/CLI as such:

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; }
}

While debugging, I can see the serializer pulling the value from the buffer property with data in tact. When the deserializer runs I see it pushing data into the buffer property, however the array is filled with 0's in lieu of the data that was there before serialize. I've tried setting IsRequired = true on the ProtoMember attribute, no luck.

I have other messages defined with sbyte arrays that are deserializing fine. However, those arrays are quite short (10 maximum). The only thing that stands out here to me is the length of this array. Help! :-)

Edit: I guess I should also mention that I'm using v1 r282.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柒七 2024-09-22 07:24:20

这里的错误是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; }
        }    
    }
}

The error here is that protobuf-net (in line with the protobuf-spec) deserializes list (etc) data by appending data. And in "v1" (the version you are using) it always runs the constructor. So when deserializing, it runs the constructor (creates an array length 4000), then processes the data and appends another 4000 items. If you check, you'll find the array is now 8000 long (you'll be glad to hear that it doesn't resize the array 4000 times...).

Fixes:

  • in v2 (not really quite released, this is for info only) you can suppress the constructor completely
  • or just remove the array creation in the ctor, and assign via the set instead (perhaps add a static factory method that does this for you, to save you some code)

The following test rig (translated to C# for my convenience, sorry) works fine:

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; }
        }    
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文