TLDR;我试图序列化/反序列化对象图预分配的对象图的所有成员值
[ProtoContract]
class Node {
[ProtoMember(1)] int data;
[ProtoMember(2)] string moreData;
[ProtoMember(3)] Node otherNodeInSameGraph;
LargeData thisComesFromAnotherSourceAndIsPreallocated;
}
[ProtoContract]
class Graph {
[ProtoMember(1)] List<Node> allNodesInGraph;
}
我的目标是能够保存图表并加载图表,其中所有节点都已分配(为了处理Node.thisComesFromAnotherSourceAndIsPreallocated
)。
完整版(对不起文字墙):
我试图使用protobuf-net在Unity游戏中实现保存游戏。我可以很好地序列化独立类,但是当涉及从Unity内置的MonoBehaviour派生的类时,我遇到了一些问题。
基本上,Unity要求 it 创建任何这些对象。通常这很好,因为它们是大型预构建对象图(包含图形和其他内容)的一部分
public class MonoBehaviour : Behaviour {
public MonoBehaviour() {
throw new DontDoThisException (
"You should never allocate monobehaviours yourself, but let Unity do it"
);
}
}
在我的游戏中,我有一些东西可以简化为一群怪物,相互攻击。让我们将此模型化为
[ProtoContract]
class Monster : MonoBehaviour {
[ProtoMember(2)] public int health;
[ProtoMember(3)] public Monster whoAmITargetting;
}
我有一个SaveManager,它知道我游戏中的所有怪物。
public SaveManager : MonoBehaviour {
public static List<Monster> allMonsters;
}
当我尝试在Protobuf-net中使用它时,就会出现问题。 Protobuf-net想为我实例化这些对象(通常很好)。问题是我已经拥有了世界上所有的怪物,并希望将数据转化为这些。这变得更加复杂,因为它们互相指向。
我尝试过这样的事情:
[ProtoContract]
[ProtoInclude (100, typeof (Monster))]
class SavableBehaviour : MonoBehaviour {
[ProtoMember(1)] public long guid; // I can guarantee that these are unique.
}
[ProtoContract]
class Monster : SavableBehaviour {
// as above
}
现在,我的目标是将Monster.whoAmITargetting
序列化为GUID。当我反序列化时,我会在全局列表中查找GUI并分配对象。
[ProtoContract]
public class SerializableSurrogate
{
[ProtoMember(1)] int saveID { get; set; }
public static implicit operator SerializableSurrogate (SavableComponent comp)
{
return
comp != null
? new SerializableSurrogate { saveID = comp.saveID }
: null;
}
public static implicit operator SavableComponent (SerializableSurrogate surr)
{
return SaveManager.allMonsters.Find (i=>i.guid == surr.saveID);
}
}
这是有效的(我认为)。我可以看到代理被调用,就像我期望的那样。但是,有一个问题。当我尝试保存SaveManager.allMonsters
时,代理也会被激活,这意味着我只保存GUID,而不保存任何其他变量。
我缺少一些新颖的方法吗?
答案 0 :(得分:0)
我对团结并不十分熟悉,但我怀疑这里有一些选择;要尝试的第一件事是Serializer.Merge
而不是Serializer.Deserialize
。如果您使用的是TypeModel
API,则为Deserialize
,但会传入预先存在的实例。
另一种选择是使用自定义工厂;从内存中,此选项目前只能通过触摸RuntimeTypeModel
实例(我应该通过属性使其可用)来实现,但这可以作为创建实例的静态方法(可选择接受序列化上下文):做任何你喜欢的事情,包括(大概)要求团结。
通过下面的评论来澄清事情,我的建议改为古老的:序列化数据;不要序列化实现。 MonoBehaviour
类及其所有规则是实现。最好是序列化与之无关的东西 - 一个简单的DTO模型(可能是非常基本的,只是你的guids等) - 并且只是在序列化之前/之后映射到DTO模型/从DTO模型映射。这增加了一些代码,但它实际上解决了每个“但我的模型可以做什么限制”的问题,并且还将您与版本控制/重构问题隔离开来(如果您更改为完全不同的引擎,则无关紧要; DTO模型不受模型更改的影响,因此您需要做的就是使映射代码保持最新;您的DTO基本保持不变。)