2011-06-28 10 views
3

私はジェネリックを含むかなり複雑な継承階層を持ち、protobuf .netをシリアル化の目的で使用しようとしています。残念ながら、このケースを正しく処理することはできないようです。これは階層の様子です。最後に、これらのクラスは、私はこれらをシリアル化するには、次の試験方法を書かれているし、それは私にエラーを与えている2つの閉じ構築非ジェネリッククラスProtobuf-netジェネリック継承と閉じた構築ジェネリック型

[System.Runtime.Serialization.DataContract] 
    public class DerivedClass1 : GenericDerivedClass<string>    
    { 
     [System.Runtime.Serialization.DataMember(Order = 6)] 
     public int DerivedClass1Property { set; get; } 
    } 

    [System.Runtime.Serialization.DataContract] 
    public class DerivedClass2 : GenericDerivedClass<object> 
    { 
     [System.Runtime.Serialization.DataMember(Order = 7)] 
     public int DerivedClass2Property { set; get; } 
    } 

によって実現されている

[System.Runtime.Serialization.DataContract] 
    [ProtoBuf.ProtoInclude(1000, typeof(GenericBaseClass<object>))] 
    [ProtoBuf.ProtoInclude(1001, typeof(GenericBaseClass<string>))] 
    public abstract class BaseClass 
    { 

     public int BaseProperty1 { set; get; } 
     public int BaseProperty2 { set; get; } 

     public BaseClass() 
     { 

     } 

    } 

    [System.Runtime.Serialization.DataContract] 
    [ProtoBuf.ProtoInclude(1002, typeof(GenericDerivedClass<object>))] 
    [ProtoBuf.ProtoInclude(1003, typeof(GenericDerivedClass<string>))] 
    public abstract class GenericBaseClass<T> : BaseClass 
    { 
     /// <summary> 
     /// 
     /// </summary> 
     [System.Runtime.Serialization.DataMember(Order = 5)] 
     public T ResponseProperty 
     { 
      get; 
      set; 
     } 

     public GenericBaseClass() 
     { 
     } 
    } 

    [System.Runtime.Serialization.DataContract] 
    [ProtoBuf.ProtoInclude(1004, typeof(DerivedClass1))] 
    [ProtoBuf.ProtoInclude(1005, typeof(DerivedClass2))] 
    public abstract class GenericDerivedClass<T> : GenericBaseClass<T> 
    { 
     public int AdditionalProperty { get; set; } 

     public GenericDerivedClass() 
     { 

     } 
    } 

[TestMethod] 
    public void SerializeDeserializeAndCompare() 
    {    

     DerivedClass2 i = new DerivedClass2() { BaseProperty1 = 1, BaseProperty2 = 2, DerivedClass2Property = 3, ResponseProperty = new Object() }; 
     using (var file = System.IO.File.Create("test.bin")) 
     { 
      ProtoBuf.Serializer.Serialize(file, i); 
     } 

     using (var file = System.IO.File.OpenRead("test.bin")) 
     { 
      var o = ProtoBuf.Serializer.Deserialize<DerivedClass2>(file); 
     } 
    } 

私は取得していますエラーが

ProtoBuf.ProtoExceptionです:タイプが唯一の継承階層(CapitalIQ.DataGet.UnitTests.DataSetUnitTest + DerivedClass2)に参加することができます---> System.InvalidOperationExceptionが:タイプは1つの継承階層にのみ参加できます

これはprotobuf .netの制限ですか、私は間違ったことをしていますか?私はr282バージョンを使用しています。

おかげ Shobhitは

+0

何かがうまくいくはずです。私は現時点では "子供の義務"を持っていますが、後で見ていきます –

答えて

4

すべての属性と同じように、属性に含まれる型情報は、ジェネリック型定義からすべて閉じタイプに適用されます。このように、あなたが実際に定義されたもの(いるProtobufネットをすること)である:あなたが見ることができるように

BaseClass 
: GenericBaseClass<object> 
: GenericDerivedClass<object> 
    : DerivedClass1 
    : DerivedClass2 
: GenericDerivedClass<string> 
    : DerivedClass1 
    : DerivedClass2 
: GenericBaseClass<string> 
: GenericDerivedClass<object> 
    : DerivedClass1 
    : DerivedClass2 
: GenericDerivedClass<string> 
    : DerivedClass1 
    : DerivedClass2 

、重複がたくさんあります - 明らかに混乱しています。属性引数は型パラメータを使うことができないので、IMOはかなり奇妙な述語機構を追加するオプションを残すでしょう。 IMOでは、これを手動でモデル化することをお勧めします(ProtoIncludeの属性を削除する)。 I容疑者あなたの意図したモデルである:

いるProtobufネットはそれで作業することができ
BaseClass 
: GenericBaseClass<object> 
: GenericDerivedClass<object> 
    : DerivedClass2 
: GenericBaseClass<string> 
: GenericDerivedClass<string> 
    : DerivedClass1 

が、を説明するモデルは「V2」とRuntimeTypeModel必要です。objectが少しあることも

注意をprotobufの問題のprotobuf-netはdynamic-typeオプションでそれを偽造できますが、それは理想的ではありません。確かにobjectをシリアル化することはできませんので、テストのために文字列を置き換えました。また、BaseProperty1,BaseProperty2およびAdditionalPropertyは、現在のところシリアル化用にマークされていませんが、自明である可能性があります。とにかく

RuntimeTypeModel.Default[typeof(BaseClass)] 
    .AddSubType(10, typeof(GenericBaseClass<object>)) 
    .AddSubType(11, typeof(GenericBaseClass<string>)); 

RuntimeTypeModel.Default[typeof(GenericBaseClass<object>)] 
    .AddSubType(10, typeof(GenericDerivedClass<object>)); 
RuntimeTypeModel.Default[typeof(GenericBaseClass<object>)][5].DynamicType = true; // object! 
RuntimeTypeModel.Default[typeof(GenericDerivedClass<object>)] 
    .AddSubType(10, typeof(DerivedClass2)); 

RuntimeTypeModel.Default[typeof(GenericBaseClass<string>)] 
    .AddSubType(10, typeof(GenericDerivedClass<string>)); 
RuntimeTypeModel.Default[typeof(GenericDerivedClass<string>)] 
    .AddSubType(10, typeof(DerivedClass1)); 

DerivedClass2 i = new DerivedClass2() { BaseProperty1 = 1, BaseProperty2 = 2, DerivedClass2Property = 3, ResponseProperty = "some string" }; 
using (var file = System.IO.File.Create("test.bin")) 
{ 
    ProtoBuf.Serializer.Serialize(file, i); 
} 

using (var file = System.IO.File.OpenRead("test.bin")) 
{ 
    var o = ProtoBuf.Serializer.Deserialize<DerivedClass2>(file); 
} 

あなたはRuntimeTypeModel.Defaultを使用するを持っていない - 実際に、私は別のタイプのモデルを使用して(キャッシング)をお勧めします。デフォルトモデルはSerializer.Serializeです。カスタムモデル(TypeModel.Create)を作成する場合は、どこかに格納して、そこからSerializeなどを使用してください。

+0

あなたの素早い返信をありがとう!この例は、より複雑なクラス階層のブランチに過ぎないので、typeModelを手動で作成することは本当に複雑になる可能性があります。また、私の悪い、私は例として型パラメータとしてオブジェクトを使用しました。代わりに、Tパラメータを満たす他のオブジェクトがあります。私はそれを打ち、反射を使って自動化できるかどうかを見ていきます。しかしそうでなければ、属性を使用してそのような階層を表現できる方法がなければならないと思います。 – shomat

+1

子クラスの子の誤ったKnownType属性をコピーした後、この例外にぶつかりました。可能であれば、例外テキストに重複したクラスが含まれていると便利です。 – Shaun

関連する問題