2010-03-23 17 views
7

Imagino a utilizar la serialización XML como esto:¿Por qué XmlSerializer es tan difícil de usar?

class Foo { 
    public Foo (string name) { 
     Name1 = name; 
     Name2 = name; 
    } 

    [XmlInclude] 
    public string Name1 { get; private set; } 

    [XmlInclude] 
    private string Name2; 
} 

StreamWriter wr = new StreamWriter("path.xml"); 
new XmlSerializer<Foo>().Serialize (wr, new Foo ("me")); 

Editar: Sé que este código es incorrecto. Fue solo para mostrar cómo me gustaría usarlo.

Pero esto no funciona en absoluto:

  • XmlSerializer no es genérica. Tengo que lanzar desde y para oponerme a la (de) serialización.
  • Cada propiedad tiene que ser completamente pública. ¿Por qué no utilizamos Reflection para acceder a setters privados?
  • campos privados no pueden ser serializados. Me gustaría decorar campos privados con un atributo para que XmlSerializer los incluya.

¿Echo de menos algo y XmlSerializer realmente ofrece las posibilidades descritas? ¿Hay serializadores alternativos en XML que manejen estos casos de forma más sofisticada?

Si no es así: Estamos en 2010, después de todo, y .NET ha existido durante muchos años. La serialización XML a menudo se usa, es totalmente estándar y debe ser realmente fácil de realizar. ¿O es posible que mi comprensión sea incorrecta y que la serialización XML no deba exponer las características descritas por una buena razón?

Edit: Legacy no es una buena razón para imo. List tampoco fue genérico al principio.

(.. Siéntase libre para ajustar el subtítulo o etiquetas Si esto debe ser CW, por favor, simplemente introduce una nota)

+3

La misma razón que cavar un agujero con una pelota de baloncesto es tan difícil. ;-) –

+3

No es correcto decir que '' List' no era genérico al principio ". 'List' se introdujo en 2.0 y era una clase genérica en ese momento. La antigua 'ArrayList' no genética es una * clase * diferente * que todavía está * allí *. – AakashM

+0

Ooops. Error de mi parte. Me disculpo :) – mafu

Respuesta

10

Primero el código fijo, entonces las respuestas a sus preguntas:

public class Foo { 
    public Foo() : this("") {} 
    public Foo (string name) { 
     Name1 = name; 
     Name2 = name; 
    } 
    // note only this will be serialized 
    public string Name1 { get; private set; } 
    // this won't 
    private string Name2; 
} 

o 3.0:

[DataContract] 
class Foo { 
    public Foo (string name) { 
     Name1 = name; 
     Name2 = name; 
    } 
    [DataMember] 
    public string Name1 { get; private set; } 
    [DataMember] 
    private string Name2; 
} 

(y el uso DataContractSerializer en lugar de XmlSerializer)

XmlSerializer es no genérico Tengo que lanzar desde y para oponerme a la (de) serialización.

Es común para los serializadores. Tengo mi propio serializador, e inicialmente I hizo hacerlo completamente genérico. Y resultó ser un gran error de diseño. Enorme. No en serio. Actualmente estoy en el proceso de volver a escribir cada línea de código para desactivarlo.

Simplemente; los serializadores generalmente involucran algún nivel de reflexión (ya sea para código genérico o para el trabajo real, dependiendo de la implementación). La reflexión y los genéricos no funcionan bien, especialmente en algunos marcos como WCF. Tener tu código haciendo el lanzamiento final es un compromiso justo. Tengo un número de entradas de blog en este si realmente quiere ...

Cada propiedad tiene que ser totalmente público.

Eso es de hecho una limitación de XmlSerializer (aunque una lista/colletion sin un regulador está bien, que lo hará tiro si usted tiene un encuentro público y privado conjunto). Además, el tipo debe ser público y tener un constructor sin parámetros.

¿Por qué no utilizamos Reflection para acceder a los setters privados?

Para el rendimiento, XmlSerializer construye un conjunto sobre la marcha para hacer lo que quiera. No tiene acceso automático a las partes internas de su código. Para obtener información, estoy haciendo algo similar, pero ofrezco 2 niveles de generación; totalmente estático (en un dll desplegable), que luego solo funciona con miembros públicos, o en memoria, que puede seguir teniendo acceso a miembros privados. Supongo que querían conformarse con solo 1 modelo, lo que tiene sentido, y necesitaban "sgen", lo que dicta el primer modelo.

Los campos privados no se pueden serializar. Me gustaría decorar campos privados con un atributo para que XmlSerializer los incluya.

A continuación, utilice DataContractSerializer, que serializar cualquier miembro (incluyendo privada) marcada [DataMember].

+1

Tu blog está en mi lista de tareas pendientes;) ¡Buena explicación! – mafu

7

1: legado. XML Serializer es anterior a los genéricos. Es como con .NET 1.0.

2: Diseño de decisiones. Se supone que el serializador XML funciona con derechos muy limitados, en comparación con otras soluciones.

3: igual que 2.

Puede usar WCF DataContract serializador en partes.

Su hipótesis es "equivocado limitado". La serialización XML es supuestamente para documentos de transferencia que, en mis proyectos, son siempre clases separadas que no hacen nada más. Como tal, no tengo ningún problema con todas las limitaciones.

11

Ver XmlSerializer class. Verás que lo estás usando mal. XmlInclude tiene un propósito totalmente diferente.

que tienes razón. El serializador XML ha estado presente desde .NET 1.0. Eso es antes de tener genéricos, por cierto, por lo que es poco probable que los apoye.

También, mejores tecnologías han llegado desde entonces:

  • DataContractSerializer es más rápido, y soporta la serialización binaria
  • LINQ to XML se puede utilizar en muchos escenarios de serialización, y es mucho más flexible

Es poco probable que el serializador XML se mejore en el futuro. Te recomiendo que aprendas las otras alternativas.

+0

@Marc: 'DataContractSerializer' con' XmlDictionaryWriter.CreateBinaryWriter' no escribe binarios? –

+0

bastante justo; Lo tomaré de vuelta. –

1

No necesita el [XmlInclude] Como usted lo tiene. Puede usar [XmlElement] [XmlAttribute] ... Para describir la forma en que se serializa la clase.

Quite el [XmlInclude] y vea si eso funciona.

class Foo { 
    public Foo (string name) { 
     Name1 = name; 
     Name2 = name; 
    } 

    [XmlAttribute] 
    public string Name1 { get; set; } 

    [XmlAttribute] 
    public string Name2; 
} 

Foo myFoo = new Foo("FirstName", "LastName"); 
StreamWriter wr = new StreamWriter("path.xml"); 
XmlSerializer serializer = new XmlSerializer(typeof(Foo)); 
serializer.Serialize(wr, myFoo); 

Actualizado, las propiedades serializadas deben ser públicas.

+0

Si no me equivoco, solo puede serializar propiedades públicas. –

+0

Bueno, no funciona, ya que los instaladores respectivos son privados. - Editar: soy lento :) – mafu

+0

a su derecha, corté y pegué lo que tenía, se ha actualizado ahora. – galford13x

0

Por cierto, DataContract nunca admite la serialización binaria, se serializa a xml pero es compatible con la codificación binaria.

+0

@Kerem: DataContractSerializer con XmlDictionaryWriter.CreateBinaryWriter escribe binario. ¿A qué te refieres cuando dices que no es compatible con la "serialización binaria"? –

Cuestiones relacionadas