Protobuf-net - 啥被序列化了?

Posted

技术标签:

【中文标题】Protobuf-net - 啥被序列化了?【英文标题】:Protobuf-net - what was serialized?Protobuf-net - 什么被序列化了? 【发布时间】:2012-11-26 03:18:23 【问题描述】:

我正在尝试用 Proto-buf 替换我们现有的序列化。问题是我们目前使用 ISerializable 来检查数据是否已更改,如果数据已更改,则仅序列化原始值。这是通过使用两个可为空的变量来完成的,并且如果值已更改,则仅将 ISerializable.GetObjectData 中的原始值添加到 info 对象。

反序列化时,在 ISerializable 构造函数中,我读取了 SerializationInfo 以查找哪些成员已序列化,哪些未序列化。如果原始值未序列化,则将其值设置为当前值。 (因此节省了资源,因为它没有被序列化)。

Protobuf-net 中有没有办法让我找出哪些字段被反序列化了?如上所述,我使用 ShouldSerialize 模式不发送原始值,但是当我到达另一端时,我需要知道哪些字段被序列化才能设置原始值。

编辑:更多细节,这里是一个示例类。

[Serializable()]
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class SomeClass : ISerializable

    internal int? _key;
    internal int? _originalKey;

    internal bool ShouldSerialize_key()
    
        return _key.HasValue;
    
    [NonSerialized]
    public bool _keySpecified;

    internal bool ShouldSerialize_originalKey()
    
        return _key != _originalKey;
    
    [NonSerialized]
    public bool _originalKeySpecified;
    [OnDeserialized()]
    internal void OnDeserializedMethod(StreamingContext context)
    
        // Use this to set the _originalKey if it hasn't been specified.
        if (!_originalKeySpecified)
        
            _originalKey = _key;
        
    

如您所见,如果_originalKey 与_key 具有相同的值,则它不会被序列化。当对象被反序列化时,我想知道 _originalKey 是否被反序列化。我认为您对 _originalKeySpecified 的回答会起作用,但在上面的课程中,一旦我反序列化,_originalKeySpecified 总是错误的。 Protobuf 反序列化过程是否设置了值? (请注意,我无法使用 ShouldSerialize 属性来决定是否在反序列化时设置 _originalKey,因为它可能已从 null 更改为另一个值,我需要在保存到数据存储区时知道这一点。

【问题讨论】:

重新编辑:请参阅我的回答中的措辞:“这是一个简单的 bool 属性...” - _originalKeySpecified 不是 bool 属性,所以不是匹配它正在寻找的模式。 _keySpecified 也不是属性,请注意。 另外,请注意它不使用 both 模式:它查找 *Specified 属性,然后查找 ShouldSerialize* 方法,然后停止。所以基本上你也会把你的一些其他逻辑移到*Specified。这个顺序是因为*Specified 允许getset(分别); ShouldSerialize* 实际上只是 get,所以是第二选择。 facepalm。正如您在下面所说,它还必须是公开的。为什么它不能设置为内部工作? hmmm...它应该作为内部/私有工作; ShouldSerialize* 确实如此(我刚刚测试过) - 我会看看为什么稍后不起作用 找到并修复;致力于源,但我还没有部署 NuGet 等 【参考方案1】:

这取决于您的具体情况。例如,如果您有可为空的支持字段,那么:被序列化的字段是具有非空值的示例......即

private int? id;
[ProtoMember(n)]
public int Id 
    get  return id.GetValueOrDefault(); 
    set  id = value; 

public bool ShouldSerializeId()  return id.HasValue; 

在这里您可以简单地检查每个ShouldSerialize* 方法以查看哪些值被反序列化;任何不是的东西仍然会有null(如果它没有要反序列化的数据,它不会调用set)。

另一种选择是*Specified 模式,它被其他一些序列化程序使用(XmlSerializer、IIRC - 可能还有DataContractSerializer)。这是一个简单的 bool 属性,如果分配了值,则(由序列化程序)将其设置为 true,否则不会。同样,*Specified 的值与ShouldSerialize* 的使用相同,用于确定是否应在序列化期间处理成员。

如果我错过了您的意图,请澄清(最好用一个例子),我会尝试解释更多。

【讨论】:

我在上面添加了更多细节。

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

使用 Protobuf-Net 序列化未知子类型

Protobuf-net 序列化错误 =“一旦生成了序列化程序,就无法更改类型”

使用 protobuf-net 反序列化字典

Protobuf-Net 总是反序列化一个空列表

使用 ProtoBuf-Net,如何(反)序列化多维数组?

Protobuf-net:改变 System.Type 反序列化的方式