ProtoBuf-Net ProtoInclude 泛型类型子类

Posted

技术标签:

【中文标题】ProtoBuf-Net ProtoInclude 泛型类型子类【英文标题】:ProtoBuf-Net ProtoInclude Generic Type Subclass 【发布时间】:2012-02-23 06:20:01 【问题描述】:

我在使用从泛型类继承的对象的子类时遇到了一些 ProtoBuf-Net 问题。

我的继承树如下所示:

Node
    SomeNodeType
    SomeOtherType
    ResourceNode<T>
        ShipResource : ResourceNode<Ship>
        SomeResource : ResourceNode<SomeType>

我一直在对所有普通类型的基本 Node 类型使用 ProtoInclude。

使用 protobuf-net 实现这种层次结构的最佳方法是什么?我尝试只包含所有内容,但我得到的错误似乎源于 protobuf 试图将对象反序列化为其父对象之一。

【问题讨论】:

仅供参考,此方案将在下一个版本中使用,仅使用属性 【参考方案1】:

你可能会看到:

一个类型只能参与一个继承层次

现在,对吗?

当您回想ResourceNode&lt;T&gt; 不是封闭类型时,问题就变得更清楚了——但ResourceNode&lt;Ship&gt;ResourceNode&lt;SomeType&gt; 是。这意味着两件事:

首先,Node 需要分别了解这两者(ResourceNode&lt;Ship&gt;ResourceNode&lt;SomeType&gt;),其次:我们需要告诉ResourceNode&lt;Ship&gt; ShipResource only,以及@ 987654329@ 关于SomeResource 仅限

第一个很容易使用属性方法:

[ProtoContract]
[ProtoInclude(1, typeof(SomeNodeType)), ProtoInclude(2, typeof(SomeOtherType))]
[ProtoInclude(3, typeof(ResourceNode<Ship>))]
[ProtoInclude(4, typeof(ResourceNode<SomeType>))]
public class Node  

但是,第二个位不能在任何当前版本中清晰地表达。我们目前无法使用:

[ProtoContract]
[ProtoInclude(1, typeof(ShipResource)), ProtoInclude(1, typeof(SomeResource))]
public class ResourceNode<T> : Node  

因为这些属性适用于ResourceNode&lt;Ship&gt;ResourceNode&lt;SomeType&gt;,并且代表非法继承链。上面重复的1 是故意的,因为它们冲突,同样因为它们是并行分支。

在 v2 中,我们可以做的是明确配置这种关系:

RuntimeTypeModel.Default.Add(typeof(ResourceNode<Ship>), true)
     .AddSubType(1, typeof (ShipResource));
RuntimeTypeModel.Default.Add(typeof(ResourceNode<SomeType>), true)
     .AddSubType(1, typeof(SomeResource));

想要做的是调整解析器,使其能够将其检测为常见情况,以便您可以简单地使用属性:

[ProtoContract]
[ProtoInclude(1, typeof(ShipResource)), ProtoInclude(1, typeof(SomeResource))]
public class ResourceNode<T> : Node  

我添加了一个“待办事项”项目,但未通过测试。然而,有趣的是,在设置它时,我还发现了一个播放不愉快的场景,所以我需要先解决这个问题

【讨论】:

优秀的答案!很高兴听到它将在未来的版本中发布。解决方法目前工作正常。 (我将它添加到 ResourceNode 的静态构造函数中)。我是否认为 DynamicType 等与 protobuf 标准相差甚远? @Simie - 注意 - 静态 ctor 是 per-T,我很难猜测它何时会触发。主要是因为棘手的“何时”我会为此避免使用 .cctor。 是的,刚刚发现。我已经把它移到别的地方了。谢谢。【参考方案2】:

我遇到了完全相同的问题,但不是手动配置所有类型,下面的方法似乎适用于任何类型。在序列化/反序列化之前调用它。

private void PopulateTypes(Type t)

    foreach(object mt in RuntimeTypeModel.Default.GetTypes())
    
        MetaType theType = mt as MetaType;
        if (null != theType)
        
            if (theType.Type == t)
                return;
        
    

    Type objType = typeof (object);
    List<Type> inheritanceTree = new List<Type>();
    do
    
        inheritanceTree.Insert(0, t);
        t = t.BaseType;
     while (null != t && t != objType);

    if (!inheritanceTree.Any(gt => gt.IsGenericType))
        return;

    int n = 100;
    for (int i = 0; i < inheritanceTree.Count - 1; i++)
    
        Type type = inheritanceTree[i];
        MetaType mt = RuntimeTypeModel.Default.Add(type, true);
        mt.AddSubType(n++, inheritanceTree[i + 1]);
    

【讨论】:

以上是关于ProtoBuf-Net ProtoInclude 泛型类型子类的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RuntimeTypeModel 将 ProtoInclude 与 protobuf-net 中的类型相关联?

ProtoBuf-Net ProtoInclude 泛型类型子类

如何停止使用 Protobuf-Net 继承,直接使用继承类?

protobuf-net 中的对象继承

Protobuf-net - 如何使用 oneof

使用 Protobuf-Net 序列化未知子类型