了解 Protobuf-net 属性的序列化和反序列化

Posted

技术标签:

【中文标题】了解 Protobuf-net 属性的序列化和反序列化【英文标题】:Understanding Protobuf-net serialization and deserialization of properties 【发布时间】:2017-05-15 15:17:00 【问题描述】:

我正在使用 Protobuf-net 序列化程序进行一些测试,并且正在试验属性的序列化。基本上我想将字典(字符串,整数)存储为字典(字符串,字符串),然后在反序列化时将(字符串,字符串)转换回(字符串,整数)。然而,令我惊讶的是,它在反序列化时通过了 TestDictionary 上的 getter(然后抛出了一个空引用异常),这让我很困惑。我认为它会通过反序列化的设置器。所以,基本上我不确定属性序列化应该如何运作。我写的简单测试类如下:

[ProtoContract]
public class Class1

    [ProtoMember(2)]
    public int test;
    public Dictionary<string, int> testDictionary;
    //public Dictionary<string, string> testDictionaryString;
    [ProtoMember(3)]
    private string test2;
    [ProtoMember(4)]
    private string test3;
    [ProtoMember(5)]
    private string test4;

    public Class1()
        

    public Class1(int test)
    
        this.test = test;
            this.testDictionary = new Dictionary<string, int>();
        for (int i = 0; i < test; i++)
        
            this.testDictionary.Add("a" + i.ToString(), i);
        
        test2 = (test + 1).ToString();
        test3 = (test + 2).ToString();
        test4 = (test + 3).ToString();
    

    [ProtoMember(1)]
    public Dictionary<string, string> TestDictionary
    
        get
        
            Dictionary<string, string> temp = new Dictionary<string, string>();
            foreach (KeyValuePair<string, int> pair in this.testDictionary)
            
                temp.Add(pair.Key, pair.Value.ToString());
            
            return temp;
        
        set
        
            testDictionary = new Dictionary<string, int>();
            foreach (KeyValuePair<string, string> pair in value)
            
                testDictionary.Add(pair.Key, Convert.ToInt32(pair.Value));
            
        
    

【问题讨论】:

反序列化可能对每个键/值对执行类似obj.TestDictionary[key] = value 的操作 - 它会改变您的 getter 返回的字典。您的方法只有在首先反序列化字典然后将结果分配给您的属性时才有效。 存储int 比存储string 便宜得多,顺便说一句,所以我不会在实际代码中这样做。如果您只是在试验 API:很好 【参考方案1】:

出于序列化的目的,字典被视为列表。 您可以想象默认列表序列化是这样的(假设有一个set 可用):

var list = obj.TheProperty;
if(list == null) 
    list = new TheListType();
    obj.TheProperty = list;

do 
    list.Add(DeserializeTheItemType(reader));
 while (still that field)

但是,您可以影响它。只需添加 OverwriteTrue = true 即可满足您的需求:

[ProtoMember(1, OverwriteList = true)]
public Dictionary<string, string> TestDictionary ...

这应该更像是:

var list = new TheListType();
do 
    list.Add(DeserializeTheItemType(reader));
 while (still that field)
obj.TheProperty = list;

然而,这里的一个重要后果是Merge 将不再以通常的预期方式工作。

附带说明:您的get/set 可能应该通过nulls,因此如果testDictionarynullTestDictionary 返回null;如果TestDictionary设置null,那么testDictionary 被设置为null

【讨论】:

以上是关于了解 Protobuf-net 属性的序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?

带有枚举的 Protobuf-net 反序列化异常

无法让 Protobuf-net 与 vb.net 一起使用

意外的 protobuf-net 序列化程序行为

Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录

如何在 Protobuf-Net 中保留一个可为空值的数组?