2010-09-15 80 views
3

我原型Protobuf網以取代我們現有的一些現有的C#代碼,它正在使用[Datacontract]將序列化對象到Xml。Protobuf網.proto文件生成繼承

使用protobuffer我們可以輕鬆地與Java共享數據。因此,我對Protobuf-net的.proto文件生成非常感興趣。對於我到目前爲止測試的幾乎所有用例來說,這都很有效。

但現在繼承它是一個不同的球類遊戲。爲繼承類生成的.proto文件非常簡單 - 不包括基類的任何字段。我可以讀取生成的字節流(請參閱下面的測試)。在C#中繼承本身工作正常 - 我可以讀取生成的字節流(請參閱下面的測試)。因此,內部二進制流包含基礎類的所有字段

生成.proto:

message ProtoScholar { 
    optional string Subject = 1; 
} 

如果我能理解字節流是怎麼寫出來,我可以手動創建相應的.proto文件。

任何人在使用protobuf-net創建一個用於繼承的.proto文件方面有任何經驗嗎?

有關如何爲繼承創建數據流的任何信息都很棒。

我的DataModel如下:

[DataContract] 
[ProtoInclude(7, typeof(ProtoScholar))] 
public class ProtoAlien 
{ 

    [DataMember(Order = 1)] 
    public string Name 
    { 
     get; 
     set; 
    } 


    [DataMember(Order = 2)] 
    public double? Average 
    { 
     get; 
     set; 
    } 

    [DataMember(Order = 3)] 
    public int? HowMuch 
    { 
     get; 
     set; 
    } 

    [DataMember(Order = 4, IsRequired = true)] 
    public Height Length 
    { 
     get; set; 
    } 


    [DataMember(Order = 5, IsRequired = true)]  
    public Character Personality 
    { 
     get; 
     set; 
    } 

    [DataMember(Order = 6, IsRequired = true)]  
    public DateTime When 
    { 
     get; set; 
    } 

    public enum Height 
    { 
     Short = 1, 
     Medium, 
     Tall 
    } 

    public enum Character : long 
    { 
     Wasp = 1717986918, 
     BumbleBee, 
     WorkerBee, 
     Hornet, 
     Queen 
    }   
} 

[DataContract()] 
public class ProtoScholar : ProtoAlien 
{ 

    [DataMember(Order=1)] 
    public string Subject 
    { 
     get; set; 
    } 

} 

我NUnit測試看起來是這樣的:

[Test] 
    public void TestInheritanceSupport() 
    { 

     var protoBuffer = new ProtoScholar 
     { 
      Name = "Ben11", 
      HowMuch = null, 
      Length = ProtoAlien.Height.Tall, 
      Personality = ProtoAlien.Character.WorkerBee, 
      When = new DateTime(2010, 4, 1, 2, 33, 56, 392), 
      Subject = "Alien Economics" 
     }; 


     using (var ms = new MemoryStream()) 
     { 

      var proto = Serializer.GetProto<ProtoScholar>(); 
      Console.WriteLine(proto); 

      //Serialize to a Memory Stream 
      Serializer.Serialize(ms, protoBuffer); 

      Console.WriteLine(ms.Length); 
      ms.Position = 0; 
      var deserializedProtoBuffer = Serializer.Deserialize<ProtoScholar>(ms); 

      Assert.AreEqual("Ben11", deserializedProtoBuffer.Name); 

      Assert.Null(deserializedProtoBuffer.HowMuch); 
      Assert.AreEqual(ProtoAlien.Height.Tall, deserializedProtoBuffer.Length); 

      Assert.AreEqual(ProtoAlien.Character.WorkerBee, deserializedProtoBuffer.Personality); 
      Assert.AreEqual(new DateTime(2010, 4, 1, 2, 33, 56, 392), deserializedProtoBuffer.When); 
      Assert.AreEqual("Alien Economics", deserializedProtoBuffer.Subject); 

     } 

    } 

回答

2

由於繼承不是核心規範的一部分,我基本上代表了這個使用封裝。所以你[ProtoInclude]映射到:

message ProtoAlien { 
    // other fields 1 thru 6 [snip] 
    optional ProtoScholar ProtoScholar = 7; 
} 
message ProtoScholar { 
    optional string Subject = 1; 
} 

GetProto<T>()正在經歷V2檢修,所以它應該支持幾個這些場景。

+0

好吧,我會給出一個去。在沒有核心規範的情況下,封裝方法是有意義的。但是將基類封裝到繼承類中會更有意義嗎? – 2010-09-16 11:06:33

+0

確實!從.proto文件生成java代碼,它正在工作。 – 2010-09-16 11:43:35

+0

@André在一般情況下,創建了一些問題,正確地將事物表示爲他們的子/超類型。即如果prop是'SomeBaseType',並且你想給它一個'SomeSuperType'實例。在超類型封裝中,我們只根據消息結構知道「SomeBaseType」。所以繼承不會在電線上工作。 – 2010-09-16 12:45:10