我在ProtoBuf-Net中遇到了一些问题,它有一个从泛型类继承的对象的子类。
我的继承树是这样的:
Node
SomeNodeType
SomeOtherType
ResourceNode<T>
ShipResource : ResourceNode<Ship>
SomeResource : ResourceNode<SomeType>
我已经在所有普通类型的基本节点类型上使用了ProtoInclude。
使用protobuf-net实现这种层次结构的最佳方式是什么?我试着只包括所有内容,但我遇到了一些错误,这些错误似乎源于protobuf试图将对象取消序列化为其父对象之一。
您可能看到:
一个类型只能参与一个继承层次结构
现在,对吧?
当您回忆起ResourceNode<T>
不是一个封闭类型,但ResourceNode<Ship>
和ResourceNode<SomeType>
是时,问题就变得更清楚了。这意味着两件事:
首先,Node
需要分别了解两者(ResourceNode<Ship>
和ResourceNode<SomeType>
),其次:我们需要告诉ResourceNode<Ship>
关于ShipResource
仅,而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));
我想要做的是调整解析器,使其能够将其作为常见情况进行检测,以便可以简单地使用属性:
[ProtoContract]
[ProtoInclude(1, typeof(ShipResource)), ProtoInclude(1, typeof(SomeResource))]
public class ResourceNode<T> : Node { }
我已经添加了一个"待办事项"项目和失败的测试。然而,有趣的是,在设置时,我还发现了一个场景,其中有些东西玩得不开心,所以我需要修复第一个
我遇到了完全相同的问题,但下面的方法似乎适用于任何类型,而不是手动配置所有类型。在序列化/反序列化之前调用它。
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]);
}
}