使用DataContractSerializer序列化循环对象引用不起作用 [英] Serializing cyclic object references using DataContractSerializer not working

查看:91
本文介绍了使用DataContractSerializer序列化循环对象引用不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建XNA游戏,并且试图完全保存游戏/地图等状态,然后能够从完全相同的状态加载和恢复.

I'm building an XNA game and I'm trying to save game/map etc. state completely, and then be able to load and resume from exactly the same state.

我的游戏逻辑由相当复杂的元素(用于序列化)组成,例如引用,委托等.我已经进行了数小时的研究,并决定最好使用DataContractSerializer保留对象引用. (我也参加了代表会议,但这是另一个主题)我没有问题,可以序列化和反序列化状态,正确,完整地重新创建对象,字段,列表,甚至对象引用.但是我有一个循环引用的问题.考虑这种情况:

My game logic consists of fairly complex elements (for serializing) such as references, delegates etc. I've done hours of research and decided that it's the best to use a DataContractSerializer that preserves the object references. (I also got around for delegates but that's another topic) I have no problem serializing and deserializing the state, re-creating the objects, the fields, lists, and even object references correctly and completely. But I've got a problem with cyclic references. Consider this scenario:

class X{
   public X another;
}

//from code:
X first = new X();
X second = new X();
first.another = second;
second.another = first;

尝试序列化X会导致抱怨循环引用的异常.如果我注释掉最后一行,则可以正常工作.好吧,我可以想象为什么会这样,但是我不知道如何解决.我读过某处可以使用DataContract属性并将IsReference设置为true,但是它对我没有任何改变-仍然出现错误. (无论如何,我还是想避免它,因为我正在处理的代码是可移植的代码,并且可能有一天也可以在Xbox上运行,而Xbox的可移植库不支持DataContract所在的程序集.)

Trying to serialize X will result in an exception complaining about cyclic references. If I comment out the last line it works fine. Well, I can imagine WHY it is happening, but I have no idea HOW to solve it. I've read somewhere that I can use the DataContract attribute with IsReference set to true, but it didn't change anything for me -- still got the error. (I want to avoid it anyway since the code I'm working on is portable code and may someday run on Xbox too, and portable library for Xbox doesn't support the assembly that DataContract is in.)

以下是要序列化的代码:

Here is the code to serialize:

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

我正在从此类中调用此代码:

and I'm calling this code from this class:

[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序列化程序是以某种方式充当默认"序列化器.现在,我已经标记了所有对象,并且现在一切正常.现在,我有了模型中的循环引用,没有问题.

SOLUTION: Just a few minutes ago, I've realized that I wasn't marking the fields with DataMember attribute, and before I added the DataContract attribute, the XNA serializer was somehow acting as the "default" serializer. Now, I've marked all the objects, and things are working perfectly now. I now have cyclic references with no problem in my model.

推荐答案

如果您不想使用[DataContract(IsReference=true)],那么DataContractSerializer将无济于事,因为该属性用引用就能解决问题的东西.

If you don't want to use [DataContract(IsReference=true)] then DataContractSerializer won't help you, because this attribute is the thing that does the trick with references.

因此,您应该寻找替代的序列化器,或者编写一些序列化代码,将您的图形转换为某种常规表示形式(例如节点列表+它们之间的链接列表),然后将其转换回来,然后序列化该简单结构.

So, you should either look for alternative serializers, or write some serialization code that transforms your graphs into some conventional representation (like a list of nodes + a list of links between them) and back, and then serialize that simple structure.

如果您决定使用DataContract(IsReference=true),下面的示例对您的图形进行了序列化:

In case you decide to use DataContract(IsReference=true), here's a sample that serializes your graph:

[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>

这篇关于使用DataContractSerializer序列化循环对象引用不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆