Warning: DataContractSerializer won’t call your constructor!
Consider the following naïve data contract:
[DataContract]
public class Data
{
private int[] array;
public Data()
{
this.array = new int[13];
}
public int Length { get { return this.array.Length; } }
}
It looks ok, right? Let’s use it then:
DataContractSerializer serializer = new DataContractSerializer(typeof(Data));
Data data = new Data();
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream, data);
stream.Position = 0; // Rewind
data = (Data)serializer.ReadObject(stream);
Console.WriteLine(data.Length); // throws a NullReferenceException
}
Why was this.array not initialized? Well, I gave the answer away in the title; the constructor was never called. It turns out that DataContractSerializer (and BinaryFormatter, by the way), unlike XmlSerializer, creates an uninitialized (without calling any constructors) instance of the type it’s de-serializing. Then data members are de-serialized.
In the example above, a very simple change will fix the issue. If you’re running .Net 3.5 SP1 or later (and you should be), the DataContractSerializer can serialize types without the [DataContract] attribute, i.e. Plain Old CLR Object (POCO) types, as long as the type is public and has a parameter-less constructor (regardless of its visibility) – just like XmlSerializer. And yes, you guessed it, in this case, the constructor will be called.
What if you don’t want to define a parameter-less constructor, or if this isn’t a viable option? You should use one of the serialization callbacks listed in the following article: https://msdn.microsoft.com/en-us/library/ms733734(v=vs.110).aspx
Here’s an example:
[DataContract]
public class Data
{
private int[] array;
public Data()
{
Initialize();
}
private void Initialize()
{
this.array = new int[13];
}
[OnDeserializing]
private void SetValuesOnDeserializing(StreamingContext context)
{
Initialize();
}
public int Length { get { return this.array.Length; } }
}