2011-09-30 52 views
14

我在什麼地方閱讀ProtoBuf.NET的筆者評論:與ProtoBuf.NET序列化是不帶標記的成員

有選項來自動推斷出的數字,但這是脆,不建議使用。只有在你知道你永遠不需要添加更多成員時才使用它(它按字母順序排列,所以添加一個新的AardvarkCount將會破壞所有內容)。

這正是那種情況我感興趣的:)

我有一些類似於,我想序列上使用Protocol Buffers遠程機器上生成結果的地圖,減少的情況(例如, map-reduce的「map」側),稍後再讀取它們並將這些結果合併以進一步處理(例如「reduce」側)。

我不想在每個可能的類上啓動一個屬性裝飾馬拉松,我可能會在這個過程中序列化,而且我發現協議緩衝區非常誘人,因爲我可以用Mono創建結果並消耗它們毫不費力地在MS.NET上,反之亦然...

沒有預先標記成員的明顯缺點並沒有打擾我完全相同的軟件版本生成/消費,所以我不需要擔心關於新成員彈出代碼和搞亂我的整個計劃...

所以總之,我的問題是:

  • 我該怎麼做(使用ProtoBuf.NET序列化,無需標記/自行構建Meta類)?
  • 我的計劃中有沒有明顯漏洞?
+0

您是否必須隨時存儲這些結果,或者數據是否始終存在?你有多確定兩端會同步?除此之外,它聽起來像應該很好... –

回答

8

如果你可以用一個單一屬性住,那麼訣竅是:

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)] 
    public class WithImplicitFields 
    { 
     public int X { get; set; } 
     public string Y { get; set; } 
    } 

這裏有2個選項; AllPublic工程如XmlSerializer - 公共屬性和字段序列化(使用字母順序來選擇標籤號碼); AllFields有點像BinaryFormatter - 字段被序列化(再次,字母)。

我不記得v2 API是否可用;我知道這是我的事情清單,以確保工作!但是,如果你想在V2中沒有任何屬性,我相信我可以添加一個Add(ImplicitFields)過載。

只要2個末端永遠不會失步,這就好了。如果您存儲了數據,或者沒有在「步驟」中對兩端進行版本化,則可能會出現問題。另請參閱關於枚舉的intellisense註釋(它幾乎重複了您已經知道的警告)。

+0

謝謝馬克。我開始在類定義中看到ProtoContract的生命跡象,現在我正在使用v2 ...我試圖讓這個沒有屬性的工作,我會很高興得到一個Add(ImplicitFields )重載,因爲這使得代碼更清潔... – damageboy

+1

我還有一個願望,就是讓ImplicitFields爲「遞歸」,即如果我有一個包含列表的類X,並且使用Add(ImplicitFields ),我希望這可以在整個類鏈中傳播。 – damageboy

+0

@damageboy或許可以解決這個問題的方法是在TypeModel級別 - 那麼你可以使用默認的類型模型。這實際上現在InferByName(類似但略微不同)的作品。 –

1

我有同樣的問題,並且我已經用TypeModel解決了它。它是基於通過它們的名字排序屬性(但它不檢查setter/getter屬性存在或序列化能力給定類型的):

[TestFixture] 
public class InferredProtoPoc 
{ 
    [Test] 
    public void UsageTest() 
    { 
     var model = TypeModel.Create(); 
     // Dynamically create the model for MyPoco 
     AddProperties(model, typeof(MyPoco)); 
     // Display the Generated Schema of MyPoco 
     Console.WriteLine(model.GetSchema(typeof(MyPoco))); 

     var instance = new MyPoco 
     { 
      IntegerProperty = 42, 
      StringProperty = "Foobar", 
      Containers = new List<EmbeddedPoco> 
      { 
       new EmbeddedPoco { Id = 12, Name = "MyFirstOne" }, 
       new EmbeddedPoco { Id = 13, Name = "EmbeddedAgain" } 
      } 
     }; 

     var ms = new MemoryStream(); 
     model.Serialize(ms, instance); 
     ms.Seek(0, SeekOrigin.Begin); 
     var res = (MyPoco) model.Deserialize(ms, null, typeof(MyPoco)); 
     Assert.IsNotNull(res); 
     Assert.AreEqual(42, res.IntegerProperty); 
     Assert.AreEqual("Foobar", res.StringProperty); 
     var list = res.Containers; 
     Assert.IsNotNull(list); 
     Assert.AreEqual(2, list.Count); 
     Assert.IsTrue(list.Any(x => x.Id == 12)); 
     Assert.IsTrue(list.Where(x => x.Id == 12).Any(x => x.Name == "MyFirstOne")); 
     Assert.IsTrue(list.Any(x => x.Id == 13)); 
     Assert.IsTrue(list.Where(x => x.Id == 13).Any(x => x.Name == "EmbeddedAgain")); 
    } 

    private static void AddProperties(RuntimeTypeModel model, Type type) 
    { 
     var metaType = model.Add(type, true); 
     foreach (var property in type.GetProperties().OrderBy(x => x.Name)) 
     { 
      metaType.Add(property.Name); 
      var propertyType = property.PropertyType; 
      if (!IsBuiltinType(propertyType) && 
       !model.IsDefined(propertyType) && 
       propertyType.GetProperties().Length > 0) 
      { 

       AddProperties(model, propertyType); 
      } 
     } 
    } 

    private static bool IsBuiltinType(Type type) 
    { 
     return type.IsValueType || type == typeof (string); 
    } 
} 

public class MyPoco 
{ 
    public int IntegerProperty { get; set; } 
    public string StringProperty { get; set; } 
    public List<EmbeddedPoco> Containers { get; set; } 
} 

public class EmbeddedPoco 
{ 
    public int Id { get; set; } 
    public String Name { get; set; } 
} 

這就是你運行它得到了什麼。

message EmbeddedPoco { 
     optional int32 Id = 1; 
     optional string Name = 2; 
    } 
    message MyPoco { 
     repeated EmbeddedPoco Containers = 1; 
     optional int32 IntegerProperty = 2; 
     optional string StringProperty = 3; 
    } 

爲了提高性能,您可以選擇編譯TypeModel,和/或存儲生成的proto以備將來使用。但是請注意,如果poco(普通舊容器對象)不斷髮展,對Protocol Buffer的隱藏依賴可能會長期存在危險。

相關問題