ProtoBuf-Net ProtoInclude通用类型子类

时间:2012-02-23 06:20:01

标签: protobuf-net

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

我的继承树看起来像这样:

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

我一直在所有普通类型的基本节点类型上使用ProtoInclude。

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

2 个答案:

答案 0 :(得分:4)

你可能会看到:

  

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

此刻,对吧?

当您回想起ResourceNode<T>不是封闭类型 - 但ResourceNode<Ship>ResourceNode<SomeType> 时,问题会变得更清晰。这意味着两件事:

首先,Node需要分别了解这两个(ResourceNode<Ship>ResourceNode<SomeType>),其次:我们需要告诉ResourceNode<Ship>关于ShipResource < strong>仅,而ResourceNode<SomeType>仅约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<Ship>ResourceNode<SomeType> ,并且代表非法继承链。上面重复的1是故意的,因为它们是冲突,因为它们是并行分支。

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

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

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

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

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

答案 1 :(得分:1)

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

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