2011-08-27 87 views
1

我已經開發了一個應用程序,旨在發送數據從客戶端到服務器和回等使用序列化的對象。Protobuf網例外與未知的子類

對於這個應用程序,我決定protobuf-net將是一個很好的選擇(特別是它處理可變長度的對象)。

但是,當從客戶端發送一個對象到服務器或反之亦然時,我所知道的是該對象將是'ReplicableObject'的某個子類。因此,我使用:

Serializer.SerializeWithLengthPrefix(stream, ro, PrefixStyle.Base128); 

在哪裏「RO」是從ReplicableObject子類的類型的對象。

不過,我得到這個異常:

類型的未處理的異常 'ProtoBuf.ProtoException' 發生在 的protobuf-net.dll

其他信息:序列化過程中發現意外的類型; ProtoIncludeAttribute中必須包含 類型;發現MessageObject 作爲ReplicableObject

在這種特定情況下通過了,我想送MessageObject

由於protobuf-net有一些珍貴的文檔,所以我被困在做什麼。我在這裏和那裏嘗試了一些屬性無濟於事。

任何幫助表示讚賞。

編輯:我應該說清楚,這些子類可能不是我寫的。

+0

我剛剛從幾天的路程返回。我會在稍後看看 –

回答

1

Protobuf是基於合同的序列化格式,設計爲獨立於平臺。因此,類型元數據包含在網絡中,因爲它不適用於平臺之間。即使繼承不是核心protobuf規範的一部分。

protobuf網作爲具體實施引入了繼承支持(通過一些煙霧和鏡子),但理想的應該還是可以預先定義預期的類型 - 完全一樣,其他串行如XmlSerializerDataContractSerializer。這可以通過使用[ProtoInclude(...)]來指定預期的具體類型來完成。

如果您確實無法預先告知實際類型,還有一個DynamicType選項,該選項將AssemblyQualifiedName寫入流中。如果你對這條路線感興趣,那麼請注意格式的「跨平臺」功能開始崩潰,但它對於.NET到.NET的目的非常有用。

在最簡單的,一個包裝如:

[ProtoContract] 
public class SomeWrapper { 
    [ProtoMember(1, DynamicType = true)] 
    public object Value {get;set;} 
} 

總結你的對象是它應該表現(在V2中至少一個; DynamicType並未V1存在)。完整示例:

[TestFixture] 
public class SO7218127 
{ 
    [Test] 
    public void Test() 
    { 
     var orig = new SomeWrapper {Value = new SubType { Foo = 123, Bar = "abc"}}; 
     var clone = Serializer.DeepClone(orig); 
     Assert.AreEqual(123, orig.Value.Foo); 
     Assert.AreEqual("abc", ((SubType) clone.Value).Bar); 
    } 
    [ProtoContract] 
    public class SomeWrapper 
    { 
     [ProtoMember(1, DynamicType = true)] 
     public BaseType Value { get; set; } 
    } 
    [ProtoContract] 
    public class BaseType 
    { 
     [ProtoMember(1)] 
     public int Foo { get; set; } 
    } 
    [ProtoContract] 
    public class SubType : BaseType 
    { 
     [ProtoMember(2)] 
     public string Bar { get; set; } 
    } 
}