[WCF] XMLSerializer VS DataContractSerializer

 

Este artículo nace de una curiosidad que me pasó el otro día al trabajar con un DataContractSerializer. Para empezar, tengamos como ejemplo la siguiente clase:

Code Snippet
  1. public class ExampleClass
  2. {
  3.     public int A;
  4.     public int B;
  5.     public int C;
  6. }

Serializar algo así, no es complicado. Como son tipos básicos, ni siquiera tenemos que añadir atributos a las propiedades. Así pues, escribiendo este código XML permitirá instanciar una clase de tipo  ExampleClass empleando un XMLSerializer:

 

Code Snippet
  1. <ExampleClass>
  2.   <C>3</C>
  3.   <A>1</A>
  4.   <B>2</B>
  5. </ExampleClass>

Code Snippet
  1. {ConsoleApplication.ExampleClass}
  2.     A: 1
  3.     B: 2
  4.     C: 3

Usando el XMLSerializer, comprobaremos que se instancia una clase ExampleClass donde el valor de C es 3, el de A es 1 y el de B es 2. ¿Sencillo, no? Bueno, pues ahora vamos a hacer lo mismo pero con un DataContractSerializer. Lo único que tenemos que hacer es modificar el XML para añadirle los atributos de forma que sean compatibles con el esquema de DataContract. Una vez hecho esto, simplemente lo deserializamos y esto es lo que ocurre:

Code Snippet
  1. {ConsoleApplication.ExampleClass}
  2.     A: 0
  3.     B: 0
  4.     C: 3

Podemos ver que sólo ha serializado el valor de la propiedad C, que es la primera que aparece en el XML y del resto ha pasado de largo. Esto ha ocurrido porque el serializador coge la primera propiedad y busca las siguientes a partir de la primera, en estricto orden alfabético. Es decir, si en el XML lo cambiamos del siguiente modo, veremos como efectivamente asigna la B y la C, pero no la A:

Code Snippet
  1. <ExampleClass xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  2.   <B>2</B>
  3.   <C>3</C>
  4.   <A>1</A>
  5. </ExampleClass>

Y esta es la salida que obtenemos:

Code Snippet
  1. {ConsoleApplication.ExampleClass}
  2.     A: 0
  3.     B: 2
  4.     C: 3

Bien, podemos hacer una cosa. Para evitar tener problemas al deserializar, podemos primero instanciar una clase del tipo que queramos trabajar y serializarla. Luego ya podemos trastear con el XML y asignarle los valores necesarios sin ningún tipo de problemas. Pero claro, eso no soluciona nuestro problema. Si lo que quiero es crear XML rápidos de prototipados y a mano (sí, soy un temerario, ¿y qué? Sonrisa) , con una gran cantidad de campos es muy fácil que me confunda y que alguno no se cargue. O muchos de ellos. Y sí, esto es una limitación del DataContractSerializer. Los campos deben estar ordenados alfabéticamente. ¿Hay algún modo de paliarlo? Vamos a verlo.

La primera opción la tenemos en el parámetro Order del atributo DataMember. De este modo, podemos indicarle a la propiedad en qué lugar aparece el elemento en el fichero XML. Es la opción recomendable cuando por algún motivo, no se sigue el orden por defecto (alfabético) para serializar.

Code Snippet
  1. [DataMember(Order = 2)]
  2.         public int C;

Otra opción es usar el XMLSerializer de toda la vida. No hay forma, por lo menos por ahora, que un DataContractSerializer asigne los elementos a las propiedades sin un orden establecido.