miércoles, 3 de junio de 2009

XmlSerializer, colecciones y auto-propiedades…

Que XmlSerializer es una clase curiosa es evidente, hay multitud de maneras de controlar la serialización de un objeto y varios trucos más o menos ocultos (os recomiendo el blog de jmservera que tiene algunos posts interesantes)…

… Lo que quiero comentaros ahora es un caso que me encontré el otro día (valeeee… ayer), en concreto con las auto-propiedades que se incorporaron en C# 3.0.

En la msdn se dice que XmlSerializer es capaz de serializar propiedades ICollection o IEnumerable que sean read-only (de hecho la regla CA2227 del análisis estático se basa en esto). Pues bien, esto es cierto si entendemos como read-only que no haya setter… ni tan siquiera privado.

Es decir, esto NO funciona:

class Program
{
static void Main(string[] args)
{
XmlSerializer xml = new XmlSerializer(typeof(Foo));
using (FileStream fs = new FileStream(@"C:\temp\foo.xml",
FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
xml.Serialize(fs,new Foo());
fs.Close();
}

}
}
public class Foo
{
public Foo()
{
this.Data = new List<Bar>();
this.Data.Add (new Bar());
this.Data.Add (new Bar());
}

public List<Bar> Data { get; private set; }
int OtherData;
}
public class Bar {}

Si intentamos serializar (o deserializar da igual) recibimos una System.InvalidOperationException (con un mensaje "No se puede generar una clase temporal (result=1). error CS0200: No se puede asignar la propiedad o el indizador 'ConsoleApplication6.Foo.Data' (es de sólo lectura)".


Si transformamos la clase Foo al estilo de C# 2.0 sin usar auto-propiedades, el código funciona, siempre que no pongamos el setter privado…


… como mínimo curioso, no?


Es evidente que cuando se hizo XmlSerializer nadie pensó en un setter de propiedad privado (ya que entonces lo usual era no poner setters privados en propiedades read-only), pero con la aparición de las auto-propiedades en C# 3.0 estos son cada vez más frecuentes… así que igual habría que actualizar XmlSerializer, porque que me obliguen a usar el estilo de C# 2.0 para poder serializar las propiedades de colección no es que me guste especialmente.


Y quizá, ya puestos a pedir, C# debería incorporar auto-propiedades read-only sin necesidad de poner el setter privado y que tuviesen la misma semántica que las variables readonly: sólo podrían ser inicializadas en el constructor. Esto permitiría también que el CLR realizara determinadas optimizaciones…


Saludos!! ;-)


Como siempre esto es un crosspost de mi blog en geeks.ms ;-)

No hay comentarios: