Hay dos cosas que un constructor llama (o al menos debería hacer).
Una es reservar una cierta cantidad de memoria para el objeto y todo el mantenimiento necesario para que sea un objeto para el resto del mundo .NET (tenga en cuenta cierta cantidad de movimientos manuales en esta explicación).
La otra es poner el objeto en un estado inicial válido, tal vez en función de los parámetros; esto es lo que hará el código real en el constructor.
La deserialización hace más o menos lo mismo que el primer paso llamando al FormatterServices.GetUninitializedObject
, y luego hace más o menos lo mismo que el segundo paso estableciendo los valores de los campos equivalentes a los que se grabaron durante la serialización (que pueden requerir deserialización otros objetos para ser dichos valores).
Ahora, el estado en el que la deserialización está metiendo el objeto puede no corresponderse con el posible por cualquier constructor. En el mejor de los casos será un desperdicio (todos los valores establecidos por el constructor serán sobrescritos) y en el peor podría ser peligroso (el constructor tiene algún efecto secundario). También podría ser simplemente imposible (solo el constructor es el que toma los parámetros; la serialización no tiene forma de saber qué argumentos usar).
Podrías verlo como un tipo especial de constructor solo utilizado por la deserialización (los puristas de OO -y deberían- se estremecen ante la idea de un constructor que no construye, me refiero a esto como una analogía solamente, si Saber C++ pensar en la forma de anular new
funciona en la medida de la memoria y tienes una analogía aún mejor, aunque sigue siendo una analogía).
Ahora, esto puede ser un problema en algunos casos - tal vez tenemos readonly
campos que sólo pueden resolverse de un constructor, o tal vez tienen efectos secundarios que queremos suceda.
Una solución para ambos es anular el comportamiento de serialización con ISerializable
. Esto se serializará según una llamada al ISerializable.GetObjectData
y luego llamará a un constructor particular con los campos SerializationInfo
y StreamingContext
para deserializar (dicho constructor puede incluso ser privado, lo que significa que la mayoría de los demás códigos ni siquiera lo verán). Por lo tanto, si podemos deserializar los campos readonly
y tener los efectos secundarios que deseamos (también podemos hacer todo tipo de cosas para controlar solo lo que se serializa y cómo).
Si solo nos preocupamos de garantizar que ocurra algún efecto secundario en la deserialización que ocurriría en la construcción, podemos implementar IDeserializationCallback
y tendremos que llamar a IDeserializationCallback.OnDeserialization
cuando se complete la deserialización.
En cuanto a otras cosas que hacen lo mismo que esto, hay otras formas de serialización en .NET, pero eso es todo lo que sé. Es posible llamar usted mismo al FormatterServices.GetUninitializedObject
, salvo que tenga una fuerte garantía de que el código posterior colocará el objeto producido en un estado válido (es decir, exactamente el tipo de situación en la que se encuentra al deserializar un objeto a partir de datos producidos por serialización del mismo tipo de objeto) haciendo esto es precario y una buena manera de producir un error muy difícil de diagnosticar.
Buena pregunta. Para solucionar este problema, deberá realizar algunas correcciones de puntero/referencia durante la deserialización, lo que puede ser difícil o incluso imposible. Tenga en cuenta el hecho de que 'nuevo coche' solo se llamó una vez. Es posible que desee probar esto en 2 procesos. – leppie
posible duplicado de [DataContractSerializer no llama a mi constructor ??] (http://stackoverflow.com/questions/1076730/datacontractserializer-doesnt-call-my-constructor) –
Nota: La otra pregunta a la que me he vinculado es sobre DataContractSerializer , pero la explicación es la misma para BinaryFormatter –