2009-07-02 11 views
84

Me acabo de dar cuenta de algo loco, que asumí que era completamente imposible: al deserializar un objeto, el DataContractSerializer no llama al constructor!¿DataContractSerializer no llama a mi constructor?

tomar esta clase, por ejemplo:

[DataContract] 
public class Book 
{ 
    public Book() 
    { // breakpoint here 
    } 

    [DataMember(Order = 0)] 
    public string Title { get; set; } 
    [DataMember(Order = 1)] 
    public string Author { get; set; } 
    [DataMember(Order = 2)] 
    public string Summary { get; set; } 
} 

Cuando deserializar un objeto de esa clase, el punto de interrupción no se ve afectado. No tengo ni idea de cómo es posible, ya que es el único constructor de este objeto.

supuse que tal vez un constructor adicional fue generada por el compilador a causa del atributo DataContract, pero no pude encontrar a través de la reflexión ...

Por lo tanto, lo que me gustaría saber es lo siguiente: ¿cómo podría crearse una instancia de mi clase sin llamar al constructor?

NOTA: Sé que puedo utilizar el atributo OnDeserializing para inicializar mi objeto cuando comienza la deserialización, este no es el tema de mi pregunta.

+3

o el "OnDeserialized", cuando el objeto está deserializado, para completar los campos faltantes. –

+1

Esta pregunta cruzó por mi mente también: http://stackoverflow.com/questions/178645/how-does-wcf-deserialization-instantiate-objects-without-calling-a-constructor –

Respuesta

118

DataContractSerializer (como BinaryFormatter) No utiliza ningún constructor. Crea el objeto como memoria vacía.

Por ejemplo:

Type type = typeof(Customer); 
    object obj = System.Runtime.Serialization. 
     FormatterServices.GetUninitializedObject(type); 

La suposición es que el proceso de deserialización (o devoluciones de llamada si es necesario) se inicializará completamente.

+82

Esto es CHEATING !! – Cheeso

+0

El constructor no se debe llamar en absoluto al deserializar. Si fue llamado, entonces 1) ¿Qué hay de los recursos que ha creado en el constructor? ¡Se filtrarán! 2) Inicializas el objeto dos veces, una vez en el constructor y una vez los valores deserializados. – Dudu

+1

@Dodu a: eso no provocará una fuga b: eso (llamar al ctor) es cómo funcionan muchos serializadores; De cualquier manera, generalmente está bien como log como se entiende el comportamiento y el diseñador según –

3

Hay algunos escenarios que no serían posibles sin este comportamiento. Piense en lo siguiente:

1) Tiene un objeto que tiene un constructor que establece la nueva instancia en un estado "inicializado". A continuación, se invocan algunos métodos en esa instancia, que lo llevan a un estado "procesado". No desea crear nuevos objetos que tengan el estado "procesado", pero aún desea de serializar/deserializar la instancia.

2) Creó una clase con un constructor privado y algunas propiedades estáticas para controlar un pequeño conjunto de parámetros de constructor permitidos. Ahora puedes serializarlos/deserializarlos.

XmlSerializer tiene el comportamiento esperado. He tenido algunos problemas con XmlSerializer porque NECESITA un constructor predeterminado. Relacionado con eso, a veces tiene sentido tener instaladores de propiedad privada. Pero el XmlSerializer también necesita getter público y setter en propiedades para serializar/deserializar.

Pienso en el comportamiento de DataContractSerializer/BinaryFormatter, como suspender el estado de una instancia durante la serialización y reanudar durante la deserialización. En otras palabras, las instancias no son "construidas" sino "restauradas" a un estado anterior.

Como ya se ha mencionado, el atributo [OnDeserializing] permite mantener sincronizados los datos no serializados.

+0

No diría que "suspender el estado de una instancia" porque me acaba de ocurrir un problema donde mi DataMember estaba usando INotifyPropertyChanged y mientras no se llama al constructor, activará NotifyPropertyChanged para que el comportamiento no se suspenda. – ForceMagic

Cuestiones relacionadas