.NET XmlSerializer和对同一对象的多个引用

时间:2010-01-08 08:13:19

标签: .net xml xml-serialization object-reference

我的存储库有List<Student>List<Course>List<Enrolment>,其中注册有Enrolment.Student和Enrolment.Course,它们是前两个列表中的学生或课程之一。

当我在我的存储库中使用XmlSerializer时,它会输出冗余数据,因为它会序列化List<Student>中每个学生的所有属性,然后再次为List<Enrolment>中每个对同一学生的引用。我正在寻找一种优雅的方法来解决这个问题。

反序列化后,我可以使用反序列化创建的重复对象实例中的ID值来修复引用,但这似乎是hackish。

修复冗余输出的一种方法是XmlIgnore Enrolment.Student和Enrolment.Course,并为序列化创建另外两个属性--Enrolment.StudentID和Enrolment.CourseID。但是,在反序列化期间,由于List<Student>List<Course>的反序列化结果不可用,因此无法设置Enrolment.Student和Enrolment.Course的引用(AFAIK)。

我想到的另一种方法是在我的对象层次结构中向下排序,分别执行每个列表并控制反序列化的顺序 - 我宁愿不这样做。

另一种方法是XmlIgnore List<Enrolment>并创建一个注册序列化助手类,在其自身的反序列化完成后初始化List<Enrolment>。这似乎付出了很多努力。

其他人如何使用XmlSerializer序列化/反序列化对同一对象的多个引用?

5 个答案:

答案 0 :(得分:3)

哦序列化的痛苦: - &gt; ...

从来没有一个通用的解决方案,我想这就是为什么MS将它从Silverlight框架中剥离出来。

我从不依赖.net框架的任何自动序列化机制。对于我自己的模型和存储库,我通常知道或者可以很容易地以编程方式确定哪些属性是简单的标量(数字/字符串/等),哪些属性是其他对象的链接(以及哪些是其中的列表)。

基本上有两种情况:

1:我们只想序列化/传输对象的平面信息。在这种情况下,我只传输链接到其他对象的属性的相应ID。接收者然后可以进行后续查询以获得他们需要的所有其他对象。

2:我们希望尽可能多地传输信息,即具有多个级别的更深层次的嵌套XML,主要用于某些报告功能,仅使用XML上的一些CSS直接显示所有内容。在这种情况下,实际上希望将相同的对象多次解析到XML树中。

有时我需要稍微调整第一个场景以避免过多的后续查询调用,但通常我相处得很好。即我已经内置到我们的代码库中,我们可以指定在何时和/或在某处配置我们想要解析的其他对象。

答案 1 :(得分:2)

使用XML Serializer无法解决此问题。它没有可用于删除重复的身份概念。

您可以做的最好的事情是将对象池与其引用分开序列化。然后,您可以在反序列化后重新创建列表。

顺便说一下,你知道XmlSerializer不是特定于C#吗?

答案 2 :(得分:2)

您可以将IXmlSerializable接口实现为Enrollment,并在WriteXml方法中生成仅包含密钥的student和course XML:

<Student Id="5"/>
<Course Id="6"/>

并且在ReadXml方法中,您可以从中加载引用。您还必须将XmlIgnore属性设置为Student和Course属性。

答案 3 :(得分:0)

这听起来像是一个解决方案:

  1. XMLIgnore每个辅助 参考即Enrolment.Student&amp; Enrolment.Course
  2. 为每个辅助设备创建一个属性 用于的参考 序列化/反序列化外键 取而代之的是 - 前缀 使用XML_FK。例如XML_FK_Student&amp; XML_FK_Course
  3. 创建一个方法XML_FinalizeDeserialization 反序列化后调用加载 使用那些外国的参考 关键属性。

答案 4 :(得分:0)

您应该/可以将参考跟踪与datacontract序列化程序一起使用:

//deserilaize:
using(MemoryStream memStmBack = new MemoryStream()) {
  var serializerForth = new DataContractSerializer(
    typeof(YourType),
    null,
    0x7FFF /*maxItemsInObjectGraph*/ ,
    false /*ignoreExtensionDataObject*/ ,
    true /*preserveObjectReferences*/ ,
    null /*dataContractSurrogate*/ );

  byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
  memStmBack.Write(data, 0, data.Length);
  memStmBack.Position = 0;
  var lsBack = (YourType) serializerForth.ReadObject(memStmBack);

}
//serialize...
using(MemoryStream memStm = new MemoryStream()) {
    var serializer = new DataContractSerializer(
      typeof(YourType),
      knownTypes,
      0x7FFF /*maxItemsInObjectGraph*/ ,
      false /*ignoreExtensionDataObject*/ ,
      true /*preserveObjectReferences*/ ,
      null /*dataContractSurrogate*/ );

    serializer.WriteObject(memStm, yourType);

    memStm.Seek(0, SeekOrigin.Begin);

    using(var streamReader = new StreamReader(memStm)) {
        result = streamReader.ReadToEnd();

或使用

[Serializable]
[DataContract(IsReference = true)]