protobuf-net 序列化为基类

Posted

技术标签:

【中文标题】protobuf-net 序列化为基类【英文标题】:protobuf-net Serializing as base class 【发布时间】:2011-10-25 04:24:49 【问题描述】:

我想使用 protobuf-net 将派生类序列化为其基类。换句话说,我希望序列化过程丢弃任何类型派生的指示:

[ProtoContract]
class Base

    [ProtoMember(1)]
    public string PublicInfo  get; set; 


class Derived : Base

    public string SecretInfo  get; set; 


class Program

    static void Main(string[] args)
    
        Derived d = new Derived()
        
            PublicInfo = "public info",
            SecretInfo = "secret info"
        ;
        using (var ms = new MemoryStream())
        
            Serializer.NonGeneric.Serialize(ms, d as Base);
            ms.Seek(0, SeekOrigin.Begin);
            Base deserialized = Serializer.Deserialize<Base>(ms);
            Console.WriteLine("Deserialized type: " + deserialized.GetType());
            Console.WriteLine("Deserialized value: " + deserialized.PublicInfo);
        
        Console.ReadLine();
    

我想生成上面的程序

 Deserialized type: Base
 Deserialized value: public info

但是我得到一个关于“类型不是预期的”的异常。

如果我将[ProtoContract] 添加到Derived,则不会设置PublicInfo 字段。如果我还将[ProtoInclude(2, typeof(Derived))] 添加到Base,那么反序列化的类型是Derived,而不是我想要的Base

我错过了什么?抱歉,如果我在其他地方忽略了答案。我想我要求的是与 this question 相反的东西,尽管我宁愿不必通过 RuntimeTypeModel 显式添加字段。

【问题讨论】:

【参考方案1】:

如果您的层次结构不是太复杂,您可以考虑使用序列化成员组合派生类型,而不是从其继承。

[ProtoContract] class Generic 
  [ProtoMember(1)] public string PublicInfo  get; set; 


class Specialized 
   public Generic Generic  get; set; 
   public string SecretInfo  get; set; 

对象的某些部分是可序列化的,而某些部分是序列化不知道的。将这些混合在一个继承层次结构中并不是一个好主意。因为它不遵循专门化的OO概念。基类是可序列化的,派生类不是,但是为了继承,派生类必须支持基类已经支持的所有内容。

【讨论】:

【参考方案2】:

大多数序列化程序会对此感到窒息,因为它们设计是为了让您重现您开始时的内容。相关问题中提出的答案足够,但有点小技巧,因此确实需要RuntimeTypeModel的一点巫术。在这方面,我非常喜欢DonAndre's answer 中的解决方案,它可以保持一切都非常干净(Specialized 甚至可以是合同,包括Generic,省略SecretInfo)。

唯一要做的事情是说服它你的Derived实际上是一个代理。代理检测代码目前无法在运行时自定义,但不难欺骗它(滥用一些实现知识),即

namespace NHibernate.Proxy 
    internal interface INHibernateProxy  // pretty spectacularly evil

...
class Derived : Base, INHibernateProxy 

现在,当它发现它无法识别 Derived 时,它应该检查常见的 proxy 模式,发现它看起来很像 NHibernate 代理,并使用基本类型。真的很可怕而且很邋遢。

【讨论】:

以上是关于protobuf-net 序列化为基类的主要内容,如果未能解决你的问题,请参考以下文章

Protobuf-net 包括不可序列化基类的特定成员

Protobuf-net RuntimeTypeModel 不序列化基类的成员

限制 protobuf-net 继承“树”

我可以反序列化为 protobuf-net 中接口的只读属性吗?

Protobuf-Net:如何序列化 guid?

protobuf-net 使用啥基本序列化器来输出字节数组?