2011-06-06 108 views
9

Marc在stackoverflow上提到,protobuf-net的v2中有可能使用ProtoInclude屬性(或類似方法)來序列化/反序列化類層次結構,而無需指定基類中的每個子類型。這是否實現了?我們有一個可以在外部庫中派生的插件接口,因此無法知道派生類型是什麼。儘管我們可以在類型之間保持唯一的編號,但我無法在網絡上找到任何示例,因爲使用ProtoInclude屬性時需要指定子類型。protobuf-net繼承

如果我不知道子類是什麼,我該如何去實現與protobuf-net的繼承?

回答

16

如果你不能在屬性指定亞型(因爲它不是在編譯時知道),你有2個選項(兩者僅適用於「V2」,可作爲測試版):

  1. 使用RuntimeTypeModel而不是靜態的Serializer方法(它們現在只是RuntimeTypeModel.Default的快捷方式);講述繼承(如下所示)模型
  2. 問題

第二添加DynamicType = true[ProtoMember(...)]不是很純的protobuf - 它嵌入類型信息,我真的不愛但人們只要保持要求。第一個是我的首選。在運行時添加亞型:

var model = TypeModel.Create(); 
var type = model.Add(typeof(YourBaseType), true); 
var subTypeA = model.Add(typeof(SomeSubType), true); 
var subTypeB = model.Add(typeof(SomeOtherSubType), true); 
type.AddSubType(4, typeof(SomeSubType)); 
type.AddSubType(5, typeof(SomeOtherSubType)); 

在上述裝置中的true「使用正常規則來自動添加成員屬性」 - 也可以利用這一控制和指定的屬性(等),如果手動你喜歡。

請注意,TypeModel應該被緩存和重用(不是爲每個需要序列化的對象創建),因爲它包含一些「發出」代碼以生成方法。重新使用它會更快,並且需要更少的內存。類型模型是線程安全的,可用於在不同線程上併發地序列化/反序列化多個流。

+0

很好,謝謝。這就是我期待的,但不知道它是如何工作的。自動屬性映射是一個很好的接觸。我們打算通過預編譯postharp屬性來做到這一點,但這樣做會更好。 – 2011-06-06 06:37:14

+0

@重要的是澄清,在這種情況下,「自動」意味着「從像XmlElement,DataMember或ProtoMember」。 *還*內置支持按字母順序排列的隱式字段,但它更脆弱 - 您需要注意這一點。 – 2011-06-06 06:40:55

+0

@Marc ** 1)**我可以使用屬性定義一些具有相同基本類型的子類型,然後在運行時添加更多的子類型嗎? ** 2)**爲什麼代碼中的第3行和第4行是必需的? Arent他們多餘,如果你添加第5和第6行? – Rotem 2014-01-22 14:29:37

4

爲了進一步擴大馬克的回答,專門處理RuntimeTypeModel,這是寫的一種方式:

RuntimeTypeModel.Default[typeof(BaseClass)].AddSubType(20, typeof(DerivedClass)); 

如果從派生類派生多個類,將它們鏈接這樣

RuntimeTypeModel.Default[typeof(DerivedClass)].AddSubType(20, typeof(DerivedFromDerivedClass)); 

等。
然後,您可以像使用protobuf-net一樣使用Serializer.Serialize(file,object)
這適用於不同的項目和命名空間。

+0

非常感謝BRILLIANT。這適用於我的場景。 – Asheh 2016-05-11 14:16:02

2

通過添加輔助擴展方法:

public static class RuntimeTypeModelExt 
{ 
    public static MetaType Add<T>(this RuntimeTypeModel model) 
    { 
     var publicFields = typeof(T).GetFields().Select(x => x.Name).ToArray(); 
     return model.Add(typeof(T), false).Add(publicFields); 
    } 
} 

,您可以簡化分登記註冊類型是這樣的:

private static RuntimeTypeModel CreateModel() 
{ 
    var model = TypeModel.Create(); 
    model.Add<ExportInfo>(); 
    model.Add<RegistrationInfo>(); 
    model.Add<FactorySetupInfo>() 
     .AddSubType(101, model.Add<ServiceSetupInfo>().Type) 
     .AddSubType(102, model.Add<GenericWrapperSetupInfo>().Type) 
     .AddSubType(103, model.Add<DecoratorSetupInfo>().Type); 
    return model; 
}