使用DataContractSerializer序列化循环对象引用无效
本文关键字:对象引用 无效 循环 序列化 DataContractSerializer 使用 | 更新日期: 2023-09-27 18:15:49
我正在构建一款XNA游戏,我试图完全保存游戏/地图等状态,然后能够从完全相同的状态加载和恢复。
我的游戏逻辑包含相当复杂的元素(用于序列化),如引用、委托等。我做了几个小时的研究,并决定最好使用保留对象引用的DataContractSerializer
。(我也尝试过委托,但那是另一个主题)我对状态的序列化和反序列化,正确和完整地重新创建对象、字段、列表,甚至对象引用都没有问题。但是我有一个循环引用的问题。考虑这个场景:
class X{
public X another;
}
//from code:
X first = new X();
X second = new X();
first.another = second;
second.another = first;
尝试序列化X将导致报错循环引用的异常。如果我注释掉最后一行,它就能正常工作。嗯,我能想象为什么会这样,但我不知道如何解决它。我在某个地方读到,我可以使用DataContract
属性与IsReference
设置为真,但它没有改变任何东西对我来说-仍然得到了错误。(无论如何我想避免它,因为我正在编写的代码是可移植代码,可能有一天也会在Xbox上运行,Xbox的可移植库不支持DataContract
所在的汇编。)
class DataContractContentWriterBase<T> where T : GameObject
{
internal void Write(Stream output, T objectToWrite, Type[] extraTypes = null)
{
if (extraTypes == null) { extraTypes = new Type[0]; }
DataContractSerializer serializer = new DataContractSerializer(typeof(T), extraTypes, int.MaxValue, false, true, null);
serializer.WriteObject(output, objectToWrite);
}
}
我从这个类中调用这段代码:
[ContentTypeWriter]
public class PlatformObjectTemplateWriter : ContentTypeWriter<TWrite>
(... lots of code ...)
DataContractContentWriterBase<TWrite> writer = new DataContractContentWriterBase<TWrite>();
protected override void Write(ContentWriter output, TWrite value)
{
writer.Write(output.BaseStream, value, GetExtraTypes());
}
和反序列化:
class DataContractContentReaderBase<T> where T: GameObject
{
internal T Read(Stream input, Type[] extraTypes = null)
{
if (extraTypes == null) { extraTypes = new Type[0]; }
DataContractSerializer serializer = new DataContractSerializer(typeof(T), extraTypes, int.MaxValue, false, true, null);
T obj = serializer.ReadObject(input) as T;
//return obj.Clone() as T; //clone falan.. bi bak iste.
return obj;
}
}
被
调用public class PlatformObjectTemplateReader : ContentTypeReader<TRead>
(lots of code...)
DataContractContentReaderBase<TRead> reader = new DataContractContentReaderBase<TRead>();
protected override TRead Read(ContentReader input, TRead existingInstance)
{
return reader.Read(input.BaseStream, GetExtraTypes());
}
地点:
PlatformObjectTemplate
是我喜欢的类型。
有什么建议吗?
解决方案:就在几分钟前,我意识到我没有用DataMember
属性标记字段,在我添加DataContract
属性之前,XNA序列化器以某种方式充当"默认"序列化器。现在,我已经标记了所有的对象,现在一切都很顺利。我现在在我的模型中有循环引用,没有问题。
如果您不想使用[DataContract(IsReference=true)]
,那么DataContractSerializer
将无法帮助您,因为这个属性是处理引用的事情。
因此,您应该寻找其他序列化器,或者编写一些序列化代码,将您的图转换为一些常规表示(如节点列表+它们之间的链接列表),然后序列化该简单结构。
如果您决定使用DataContract(IsReference=true)
,这里有一个示例来序列化您的图形:
[DataContract(IsReference = true)]
class X{
[DataMember]
public X another;
}
static void Main()
{
//from code:
var first = new X();
var second = new X();
first.another = second;
second.another = first;
byte[] data;
using (var stream = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(X));
serializer.WriteObject(stream, first);
data = stream.ToArray();
}
var str = Encoding.UTF8.GetString(data2);
}
str
将包含以下XML:
<X z:Id="i1" xmlns="http://schemas.datacontract.org/2004/07/GraphXmlSerialization"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<another z:Id="i2">
<another z:Ref="i1"/>
</another>
</X>