2011-10-25 18 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; } 
} 

オブジェクトの一部にはシリアライズ可能なものがあり、一部の部分はシリアライズが認識されません。これらを1つの継承階層に混在させることは良い考えではありません。なぜならそれはOOの専門化の概念に従わないからです。基本クラスは直列化可能であり、派生クラスは継承されませんが、派生クラスは基本クラスがすでにサポートしているすべてをサポートする必要があります。彼らはあなたがして始めたものを再現できるようにするためにをを設計されているので

+0

これは素晴らしい点です。ありがとうございます。 – Gabriel

3

ほとんどシリアライザは、その上で窒息します。関連する質問で提案された答えはで十分ですですが、ハックのビットであるので、にはRuntimeTypeModelの小さなブードーが必要です。その点では、私はかなりすべてを清潔に保つDonAndre's answerのソリューションが好きです(そして、Specializedは、Genericが含まれ、SecretInfoが省略された契約でさえあります)。

行うための唯一の他の事は、あなたが実際にDerivedプロキシであること、それを説得することです。プロキシ検出コードが実行時に現在のカスタマイズではありません、それはそれはDerivedにそれを認識していない見つけたとき、しかし、今、すなわち

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

、(実装のいくつかの知識を悪用)、それをだますのは難しいことではないでしょう共通代理人のパターンをチェックし、NHibernateプロキシのように見え、ベースタイプを使用する必要があります。本当に恐ろしいとひどい。

関連する問題