【问题标题】:protobuf-net inheritanceprotobuf-net 继承
【发布时间】:2011-09-09 00:05:24
【问题描述】:

Marc 在 stackoverflow 上提到,在 v2 的 protobuf-net 中可以使用 ProtoInclude 属性(或类似方法)来序列化/反序列化类层次结构,而无需在基类中指定每个子类型。这还实施了吗?我们有一个可以在外部库中派生的插件接口,因此无法知道派生类型是什么。虽然我们可以在类型之间保持唯一编号,但是我在网上找不到任何示例,除了使用需要指定子类型的 ProtoInclude 属性。

如果我不知道子类型是什么,我将如何使用 protobuf-net 实现继承?

【问题讨论】:

    标签: c# protocol-buffers protobuf-net


    【解决方案1】:

    如果您不能在属性中指定子类型(因为在编译时不知道),您有 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 应该被缓存和重复使用(不是为每个需要序列化的对象创建),因为它包含一些“发出”代码来生成方法。重新使用它会更快并且需要更少的内存。类型模型是线程安全的,可用于在不同线程上同时序列化/反序列化多个流。

    【讨论】:

    • 太好了,谢谢。这就是我想要做的,但不确定它是如何工作的。自动属性映射是一个不错的选择。我们打算使用预编译的 postsharp 属性来做到这一点,但这要好得多。
    • @Heavy 澄清一下,在这种情况下,“自动”是指“来自 XmlElement、DataMember 或 ProtoMember 之类的东西”。 还内置了对按字母顺序排序的隐式字段的支持,但它更脆弱 - 你需要小心。
    • @Marc 1) 我可以使用属性定义一些相同基本类型的子类型,然后在运行时添加更多吗? 2) 为什么代码中的第 3 行和第 4 行是必要的?如果加上第 5 行和第 6 行,它们不是多余的吗?
    • @Rotem 1=很好,2=可能,但我喜欢明确
    • @MarcGravell 感谢您的快速响应,更重要的是 protobuf-net,太棒了!
    【解决方案2】:

    为了进一步扩展Marc的答案,专门处理RuntimeTypeModel,这是一种写法:

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

    如果您有更多从派生类派生的类,请像这样链接它们

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

    等等。
    然后,您可以使用 Serializer.Serialize(file,object),就像您通常使用 protobuf-net 一样。
    这适用于项目和命名空间。

    【讨论】:

    • 非常感谢。这非常适合我的场景。
    • 在序列化或反序列化的时候,你是如何实际使用模型的?
    【解决方案3】:

    通过添加辅助扩展方法:

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 2012-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多