2011-10-25 45 views
4

我想使用protobuf-net將派生類序列化爲其基類。換句話說,我想序列化過程中丟棄的類型派生的任何指示: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明確添加字段。

回答

4

如果您的層次結構不是太複雜,您可以考慮使用序列化成員來編寫派生類型,而不是繼承它。

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

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

但是也有一些序列化和某些部分的序列不知道你對象的某些部分。將這些組合在一個繼承層次中並不是一個好主意。因爲它沒有遵循面向對象的專業化概念。基類是可序列化的,派生類不是,但是爲了繼承,派生類必須支持基類已經支持的所有東西。

+0

這是一個很好的觀點,謝謝。 – Gabriel

3

大多數串行器會窒息,因爲他們是設計想要讓你重現你開始。在相關問題中提出的答案是就足夠了,但是有點破解,所以確實需要一點點巫毒RuntimeTypeModel。在這方面,我非常喜歡DonAndre's answer中的解決方案,它保持一切都很乾淨(並且Specialized甚至可以是合同,包括GenericSecretInfo省略)。

唯一的其他事情做會說服它,你的Derived實際上是一個代理。代理檢測代碼是不是目前在運行時可定製的,但它不會是很難騙到現在(濫用執行的一些知識),即

namespace NHibernate.Proxy { 
    internal interface INHibernateProxy {} // pretty spectacularly evil 
} 
... 
class Derived : Base, INHibernateProxy {} 

,當它發現它不承認Derived它應該檢查共同代理模式,發現它看起來很像一個NHibernate代理,並使用基類型。真是可怕又蹩腳。