2011-04-07 19 views
29

En C#, tengo una clase que tiene una propiedad derivada que se debe serializar a través de XML. Sin embargo, la serialización XML (por defecto) no serializa las propiedades read = only. Puedo evitar este definiendo una incubadora vacía, así:Forzar serialización XML para serializar la propiedad de solo lectura

public virtual string IdString 
{ 
    get { return Id.ToString("000000"); } 
    set { /* required for xml serialization */ } 
} 

Pero hay una manera más limpia más semánticamente correcta, sin llegar a escribir mi propia aplicación ISerializable?

+0

Si entiendo esto correctamente, tiene un IdString que se serializa en el archivo XML, pero se ignora cuando la clase se deserializa? –

+0

IdString siempre se derivará de la propiedad Id, que se serializará y se deserializará. – Chris

+10

En este caso, ¿por qué serializa IdString? – Justin

Respuesta

13

En resumen, no. Con XmlSerializer puede implementar IXmlSerializable (que no es trivial), o escribir un DTO básico (que es completamente de lectura y escritura) y luego traducir desde el modelo de DTO a su modelo principal.

Tenga en cuenta que en algunos casosDataContractSerializer es una opción viable, pero no ofrece el mismo control sobre el XML. Sin embargo, la DCS que puede hacer:

[DataMember] 
public int Id { get; private set; } 
+3

'IXmlSerializable' realmente funciona muy bien para este problema, especialmente si solo está serializando y no deserializando, y no es tan difícil de hacer. Echa un vistazo a esto: http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly – cjbarth

18

Sinceramente esto no parece demasiado malo para mí, siempre y cuando se documenta

Probablemente debería lanzar una excepción si el colocador se llama en realidad:

/// <summary> 
/// Blah blah blah. 
/// </summary> 
/// <exception cref="NotSupportedException">Any use of the setter for this property.</exception> 
/// <remarks> 
/// This property is read only and should not be set. 
/// The setter is provided for XML serialisation. 
/// </remarks> 
public virtual string IdString 
{ 
    get 
    { 
     return Id.ToString("000000"); 
    } 
    set 
    { 
     throw new NotSupportedException("Setting the IdString property is not supported"); 
    } 
} 
+8

¿No sería eso lo que haría que la deserialización fallara, solo por el hecho de que se lanzara esta excepción? – primfaktor

+2

@primfaktor Sí, pero como entendí la pregunta, ese es el punto (nunca se deserializará). Si ese no era el comportamiento deseado, no podría hacer nada en el colocador, ni siquiera analizar la cadena y establecer la propiedad 'Id' (posiblemente solo si aún no se ha establecido). – Justin

+1

Oh, claro. Estaba muy bajo en cafeína al escribir esto. – primfaktor

1

para tomar la solución un poco más lejos para permitir a deserialización funciona tan bien ...

public class A 
{ 
    private int _id = -1; 

    public int Id 
    { 
     get { return _id; } 
     set 
     { 
      if (_id < 0) 
       throw new InvalidOperationException("..."); 

      if (value < 0) 
       throw new ArgumentException("..."); 

      _id = value; 
     } 
    } 
} 

Esto permitirá que Id se establezca exactamente una vez en un valor mayor que o igual a 0. Cualquier intento de configurarlo dará como resultado InvalidOperationException. Esto significa que XmlSerializer podrá establecer Id durante la deserialización, pero nunca podrá ser cambiado después. Tenga en cuenta que si la propiedad es un tipo de referencia, entonces puede verificar null.

Esta puede no ser la mejor solución si tiene muchas propiedades de solo lectura para serializar/deserializar, ya que requeriría un gran número de código repetitivo. Sin embargo, he encontrado que esto es aceptable para las clases con 1-2 propiedades de solo lectura.

Todavía un truco, pero esto es al menos un poco más robusto.

Cuestiones relacionadas