J'ai une collection de classes que je veux sérialiser vers un fichier XML. Cela ressemble à ceci:
public class Foo
{
public List<Bar> BarList { get; set; }
}
Où une barre n'est qu'un wrapper pour une collection de propriétés, comme ceci:
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
Je veux marquer cela pour qu'il sorte dans un fichier XML - cela sera utilisé à la fois pour la persistance, et aussi pour rendre les paramètres via un XSLT dans une forme lisible par l'homme.
Je veux obtenir une belle représentation XML comme celle-ci:
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<BarList>
<Bar>
<Property1>Value</Property1>
<Property2>Value</Property2>
</Bar>
<Bar>
<Property1>Value</Property1>
<Property2>Value</Property2>
</Bar>
</Barlist>
</Foo>
où se trouvent tous les Bars de la Barlist avec toutes leurs propriétés. Je suis assez sûr que j'aurai besoin d'un balisage sur la définition de classe pour le faire fonctionner, mais je n'arrive pas à trouver la bonne combinaison.
J'ai marqué Foo avec l'attribut
[XmlRoot("Foo")]
et le list<Bar>
avec l'attribut
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName="Bar")]
pour essayer de dire au sérialiseur ce que je veux faire. Cela ne semble pas fonctionner cependant et je reçois juste une balise vide, ressemblant à ceci:
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<Barlist />
</Foo>
Je ne sais pas si le fait que j'utilise les propriétés automatiques devrait avoir un effet, ou si l'utilisation de génériques nécessite un traitement spécial. J'ai réussi à utiliser cela avec des types plus simples comme une liste de chaînes, mais une liste de classes m'a jusqu'ici échappé.
Juste pour vérifier, avez-vous marqué Bar comme [Sérialisable]?
De plus, vous avez besoin d'un ctor sans paramètre sur Bar, pour désérialiser
Hmm, j'ai utilisé:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Foo f = new Foo();
f.BarList = new List<Bar>();
f.BarList.Add(new Bar { Property1 = "abc", Property2 = "def" });
XmlSerializer ser = new XmlSerializer(typeof(Foo));
using (FileStream fs = new FileStream(@"c:\sertest.xml", FileMode.Create))
{
ser.Serialize(fs, f);
}
}
}
public class Foo
{
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName = "Bar")]
public List<Bar> BarList { get; set; }
}
[XmlRoot("Foo")]
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
Et cela a produit:
<?xml version="1.0"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BarList>
<Bar>
<Property1>abc</Property1>
<Property2>def</Property2>
</Bar>
</BarList>
</Foo>
Tout a l'air génial. Comme @Carl l'a dit, vous devez ajouter l'attribut [Serializable] à vos classes, mais à part cela, votre création XML devrait fonctionner.
Foo
[Serializable]
[XmlRoot("Foo")]
public class Foo
{
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName = "Bar")]
public List<Bar> BarList { get; set; }
}
Bar
[Serializable]
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
Code à tester
Foo f = new Foo();
f.BarList = new List<Bar>();
f.BarList.Add(new Bar() { Property1 = "s", Property2 = "2" });
f.BarList.Add(new Bar() { Property1 = "s", Property2 = "2" });
FileStream fs = new FileStream("c:\\test.xml", FileMode.OpenOrCreate);
System.Xml.Serialization.XmlSerializer s = new System.Xml.Serialization.XmlSerializer(typeof(Foo));
s.Serialize(fs, f);
Sortie
<?xml version="1.0" ?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BarList>
<Bar>
<Property1>s</Property1>
<Property2>2</Property2>
</Bar>
<Bar>
<Property1>s</Property1>
<Property2>2</Property2>
</Bar>
</BarList>
</Foo>
var xmlfromLINQ = new XElement("BarList",
from c in BarList
select new XElement("Bar",
new XElement("Property1", c.Property1),
new XElement("Property2", c.Property2)
));
Cela fait plus de 5 ans que cet article a été publié. Je donne mon expérience depuis juillet 2013 (.NET Framework 4.5). Pour ce que cela vaut et pour qui cela peut concerner:
Quand je définis une classe comme ça: (code VB.Net)
<Serializable> Public Class MyClass
Public Property Children as List(of ChildCLass)
<XmlAttribute> Public Property MyFirstProperty as string
<XmlAttribute> Public Property MySecondProperty as string
End Class
<Serializable> Public Class ChildClass
<XmlAttribute> Public Property MyFirstProperty as string
<XmlAttribute> Public Property MySecondProperty as string
End Class
Avec cette définition, la classe est (dé) sérialisée sans aucun problème. Voici le XML qui sort d'ici:
<MyClass> MyFirstProperty="" MySecondProperty=""
<Children>
<ChildClass> MyFirstProperty="" MySecondProperty=""
</ChildClass>
</Children>
</MyClass>
Il ne m'a fallu que deux jours pour comprendre que la solution était de laisser de côté le <XmlElement>
préfixe des éléments List (of T).