c# - valid - Serializando Listas de Clases a XML
which example is a valid visual c# xml documentation comment (4)
Tengo una colección de clases que quiero serializar en un archivo XML. Se ve algo como esto:
public class Foo
{
public List<Bar> BarList { get; set; }
}
Donde una barra es solo un contenedor para una colección de propiedades, como esta:
public class Bar
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
Quiero marcar esto para que salga a un archivo XML; esto se utilizará tanto para la persistencia como para convertir la configuración a través de un XSLT en una buena forma legible para los humanos.
Quiero obtener una buena representación XML como esta:
<?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>
donde están todas las barras en la lista de barras escritas con todas sus propiedades. Estoy bastante seguro de que necesitaré un margen de utilidad en la definición de la clase para que funcione, pero parece que no puedo encontrar la combinación correcta.
Marqué a Foo con el atributo
[XmlRoot("Foo")]
y la list<Bar>
con el atributo
[XmlArray("BarList"), XmlArrayItem(typeof(Bar), ElementName="Bar")]
en un intento de decirle al serializador lo que quiero que suceda. Sin embargo, esto no parece funcionar y acabo de recibir una etiqueta vacía, con el siguiente aspecto:
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<Barlist />
</Foo>
No estoy seguro de si el hecho de que estoy usando Automatic Properties debería tener algún efecto, o si el uso de genéricos requiere algún tratamiento especial. He conseguido esto para trabajar con tipos más simples, como una lista de cadenas, pero una lista de clases hasta ahora se me escapa.
Han pasado más de 5 años desde que se publicó este artículo. Doy mi experiencia desde julio de 2013 (.NET Framework 4.5). Por lo que vale y a quién le concierne:
Cuando defino una clase como esta: (código 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
Con esta definición, la clase se (de) serializar sin ningún problema. Este es el XML que sale de aquí:
<MyClass> MyFirstProperty="" MySecondProperty=""
<Children>
<ChildClass> MyFirstProperty="" MySecondProperty=""
</ChildClass>
</Children>
</MyClass>
Solo me tomó dos días darme cuenta de que la solución era dejar fuera el prefijo <XmlElement>
de los elementos List (of T).
Solo para verificar, ¿has marcado Bar como [Serializable]?
Además, necesita un ctor sin parámetros en Bar, para deserializar
Hmm, utilicé:
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; }
}
Y eso produjo:
<?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>
Todo se ve genial. Como @Carl dijo que necesitas agregar el atributo [Serializable] a tus clases, pero aparte de eso tu creación de XML debería funcionar.
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; }
}
Código para probar
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);
Salida
<?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)
));