“已经添加了具有相同键的项”;protobuf-net错误
本文关键字:错误 protobuf-net 添加 | 更新日期: 2023-09-27 18:12:53
我正在尝试用Marc Gravell为c#编写的protobuf替换现有的序列化器。我的代码很广泛,我的目标是能够以最小的更改进行切换。
我遇到了一个问题,我相信我知道为什么会发生,但需要帮助来克服-特别是一个解决方案,将需要在我已经存在的代码和类中进行最小的更改。我的代码很复杂,所以我创建了以下简短的示例来演示这个问题:
using System;
using System.Collections.Generic;
using System.IO;
using ProtoBuf;
namespace ConsoleApplication1
{
class program_issue
{
[ProtoContract]
public class Father
{
public Father()
{
sonny = new Son();
}
[ProtoMember(101)]
public string Name;
[ProtoMember(102)]
public Son sonny;
}
[ProtoContract]
public class Son
{
public Son()
{
Dict.Add(10, "ten");
}
[ProtoMember(103)]
public Dictionary<int, string> Dict = new Dictionary<int, string>();
}
static void Main(string[] args)
{
Father f1 = new Father();
f1.Name = "Hello";
byte[] bts = PBSerializer.Serialize(typeof(Father), f1);
Father f2;
PBSerializer.Deserialize(bts, out f2);
}
public static class PBSerializer
{
public static byte[] Serialize(Type objType, object obj)
{
MemoryStream stream = new MemoryStream();
ProtoBuf.Serializer.Serialize(stream, obj);
string s = Convert.ToBase64String(stream.ToArray());
byte[] bytes = stream.ToArray();
return bytes;
}
public static void Deserialize(byte[] data, out Father obj)
{
using (MemoryStream stream = new MemoryStream(data))
{
obj = ProtoBuf.Serializer.Deserialize<Father>(stream);
}
}
}
}
}
简而言之,当父对象被创建时,它创建一个子对象,子对象初始化一个带有一些值的字典。我假设当protobuf试图在反序列化时重建对象时,它使用相同的构造函数(因此也初始化带有值的字典),然后尝试再次推入相同的值,作为反序列化->错误的一部分。
我如何通过对代码的最小更改来克服它?
亲切的问候,Yossi .
这里最简单的选项可能是:
[ProtoContract(SkipConstructor = true)]
,正如它所说,它不会执行构造函数(或字段初始化式)。注意,如果没有数据,这将使字典为空。另一种方法可能是使用序列化回调(在加载数据之前触发):
[ProtoBeforeDeserialization]
private void Foo()
{
Dict.Clear();
}
第三种选择是使用:
[ProtoContract(SkipConstructor = true)]
:
[ProtoAfterDeserialization]
private void Foo()
{
if(Dict == null) Dict = new Dictionary<int,string>();
}
将其默认为空字典,即使没有数据。注意,您也需要从Father
执行此操作,因为它使用默认的Son
构造函数。