DataContractSerializer doesn't call my constructor?
I just realized something crazy, which I assumed to be completely impossible : when deserializing an object, the DataContractSerializer doesn't call the constructor !
Take this class, for instance :
[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; }
}
When I deserialize an object of that class, the breakpoint is not hit. I have absolutely no idea how it is possible, since it is the only constructor for this object !
I assumed that perhaps an additional constructor was generated by the compiler because of the DataContract
attribute, but I couldn't find it through reflection...
So, what I'd like to know is this : how could an instance of my class be created without the constructor being called ??
NOTE: I know that I can use the OnDeserializing
attribute to initialize my object when deserialization begins, this is not the subject of my question.
DataContractSerializer
(like BinaryFormatter
) doesn't use any constructor. It creates the object as empty memory.
For example:
Type type = typeof(Customer);
object obj = System.Runtime.Serialization.
FormatterServices.GetUninitializedObject(type);
The assumption is that the deserialization process (or callbacks if necessary) will fully initialize it.
There are some scenario's that wouldn’t be possible without this behavior. Think of the following:
1) You have an object that has one constructor that sets the new instance to an "initialized" state. Then some methods are called on that instance, that bring it in a "processed" state. You don’t want to create new objects having the "processed" state, but you still want de serialize / deserialize the instance.
2) You created a class with a private constructor and some static properties to control a small set of allowed constructor parameters. Now you can still serialize / deserialize them.
XmlSerializer has the behavior you expected. I have had a some problems with the XmlSerializer because it DOES need a default constructor. Related to that, sometimes it makes sense to have private property setters. But the XmlSerializer also needs public getter and setter on properties in order to serialize / deserialize.
I think of the DataContractSerializer / BinaryFormatter behavior like suspending the state of an instance during serialization and resuming during deserialization. In other words, the instances are not “constructed” but “restored” to an earlier state.
As you already mentioned, the [OnDeserializing] attribute makes it possible to keep non serialized data in sync.
FWIW, you can call the constructor explicitly from a [OnDeserializing] method:
[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
this.GetType().GetConstructor(System.Array.Empty<Type>()).Invoke(this, null);
}