Как избежать создания нескольких экземпляров объекта с помощью десериализации XML? - PullRequest
2 голосов
/ 21 августа 2010

У меня есть класс, который при сериализации в XML выглядит следующим образом (обобщенно для простоты):

<root>
  <resources>
    <resource name="foo" anotherattribute="value">data</resource>
    <resource name="bar" anotherattribute="value">more data</resource>
  </resource>
  <myobject name="objName">
    <resource name="foo" />
  </myobject>
</root>

Когда он десериализован, мне нужен экземпляр resource, указанный в свойствеЭкземпляр myobject должен быть тем же объектом, созданным при десериализации коллекции resources.Также, если возможно, я не хочу выводить полную сериализацию экземпляра resource в myobject, только имя.

Есть ли способ сделать это?Сейчас я рассматриваю возможность использования отдельного строкового свойства для целей сериализации, которое получает соответствующий объект от root, когда десериализатор устанавливает свойство, но это означает, что myobject ссылка на root содержит его,и я надеялся избежать этой связи.

1 Ответ

1 голос
/ 21 августа 2010

Вы не можете сделать это с XmlSerializer, потому что он не обрабатывает ссылки на объекты.

Если у вас нет каких-либо ограничений на сгенерированную схему, вы можете использовать DataContractSerializer, который также сериализуется в XML, но поддерживает ссылки. Чтобы использовать DataContractSerializer, каждый тип должен иметь атрибут DataContract, а каждый член, который вы хотите сериализовать, должен иметь атрибут DataMember:

[DataContract(Name = "root")]
public class root
{
    [DataMember]
    public List<resource> resources { get; set; }
    [DataMember]
    public myobject myobject { get; set; }
}

[DataContract]
public class myobject
{
    [DataMember]
    public string name { get; set; }
    [DataMember]
    public resource resource { get; set; }
}

[DataContract(Name = "resource", IsReference = true)]
public class resource
{
    [DataMember]
    public string name { get; set; }
    [DataMember]
    public string anotherattribute { get; set; }
    [DataMember]
    public string content { get; set; }
}

...

var serializer = new DataContractSerializer(typeof(root));
using (var xwriter = XmlWriter.Create(fileName))
{
    serializer.WriteObject(xwriter, r);
}

Обратите внимание на IsReference = true для класса resource: это то, что заставляет сериализатор обрабатывать этот класс по ссылке. В сгенерированном XML каждый экземпляр resource сериализуется только один раз:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
  <myobject>
    <name>objName</name>
    <resource z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
      <anotherattribute>value</anotherattribute>
      <content>data</content>
      <name>foo</name>
    </resource>
  </myobject>
  <resources>
    <resource z:Ref="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
    <resource z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
      <anotherattribute>value</anotherattribute>
      <content>more data</content>
      <name>bar</name>
    </resource>
  </resources>
</root>
...