2010-08-20 2 views
2

У меня есть класс, который когда сериализовать в XML выглядит следующим образом (обобщенно для простоты):Как избежать создания нескольких экземпляров объекта с десериализацией 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

Вы не можете сделать это с помощью 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> 
+0

Проблема здесь состоит в том, что полный десериализации 'resource' объекты должны находиться в пределах' resources' тега, никогда в 'myobject' тега. Я подозреваю, что это, вероятно, легко отсортировать, просто удостоверившись, что «ресурсы» сначала сериализованы. Кроме того, у меня не может быть дополнительных атрибутов для Id и Ref, он уже получил имя для использования в качестве ссылки. – Flynn1179

+0

Действительно, вы можете изменить порядок, в котором свойства сериализованы. И, как я уже сказал, это решение работает только в том случае, если вам не нужна схема XML ... Если вы хотите, чтобы это было точно так, как вы описали в своем вопросе, я думаю, вам придется обрабатывать сериализацию вручную, реализуя IXmlSerializable –

Смежные вопросы