问题描述
我在C ++ / CLI中定义了这样一个类:
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; }
}
在调试时,我可以看到序列化程序从buffer属性中提取值数据完整无缺。当反序列化器运行时,我看到它将数据推入buffer属性,但是该数组填充了0,代替了序列化之前的数据。我尝试在ProtoMember属性上将IsRequired = true设置,不走运。
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.
我还有其他消息,这些消息使用反序列化的sbyte数组定义。但是,这些数组很短(最多10个)。对我而言,唯一突出的是该数组的长度。帮帮我! :-)
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! :-)
编辑:我想我也应该提到我正在使用v1 r282。
I guess I should also mention that I'm using v1 r282.
推荐答案
此处的错误是protobuf-net(与protobuf-spec一致)通过追加数据反序列化列表(etc)数据。在 v1(您使用的版本)中,它始终运行构造函数。因此,在反序列化时,它将运行构造函数(创建长度为4000的数组),然后处理数据并附加另外4000个项目。如果进行检查,您会发现数组现在长8000(您很高兴听到它没有将数组调整大小4000倍...)。
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...).
修复:
- 在v2中(尚未完全发布,这仅供参考),您可以完全禁止使用构造函数
- 或只是删除ctor中的数组创建,而是通过集合进行赋值(也许添加一个静态工厂方法来为您执行此操作,以节省一些代码)
以下测试装备(为方便起见,已转换为C#)工作正常:
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; }
}
}
}
这篇关于protobuf-net不反序列化sbyte数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!