protobuf-net 出现“已添加具有相同密钥的项目”错误

Posted

技术标签:

【中文标题】protobuf-net 出现“已添加具有相同密钥的项目”错误【英文标题】:"An item with the same key has already been added" error with protobuf-net 【发布时间】:2011-11-01 11:42:44 【问题描述】:

我正在尝试用 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 在反序列化时尝试重建对象时,它使用相同的构造函数(因此也用值初始化字典),然后尝试再次推送相同的值作为反序列化的一部分 -> 错误。

如何通过对代码的最小更改来克服它?

亲切的问候, 尤西。

【问题讨论】:

小注:“protobuf-net”只是一种实现;还有其他 C# protobuf 实现。我只是提到这个来解释我为什么改变标题 【参考方案1】:

这里最简单的选择可能是:

[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 构造函数。

【讨论】:

非常感谢,马克。我尝试了你的建议,他们解决了我的问题。我相信我会选择第三种选择(资源要求最低)。尤西。

以上是关于protobuf-net 出现“已添加具有相同密钥的项目”错误的主要内容,如果未能解决你的问题,请参考以下文章

当我转到共享服务管理中的“搜索设置”页面时,出现此错误:“已添加具有相同密钥的项目。”

已添加具有相同密钥的项目 - 仅处于发布模式

Windows Azure:“已添加具有相同密钥的项目。”选择时抛出异常

Ionic.Zip ArgumentException(已添加具有相同密钥的项目)

IStatefulServiceReplica.Open 上的错误 - 已添加具有相同密钥的项目

已添加具有相同密钥的项目 C# -Ionic.Zip